aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/res/layout/input_view.xml2
-rw-r--r--java/res/layout/more_suggestions.xml2
-rw-r--r--java/res/values-be/donottranslate-more-keys.xml23
-rw-r--r--java/res/values-ky/donottranslate-more-keys.xml24
-rw-r--r--java/res/values-land/dimens.xml1
-rw-r--r--java/res/values-ro/donottranslate-more-keys.xml2
-rw-r--r--java/res/values-ru/donottranslate-more-keys.xml4
-rw-r--r--java/res/values-sk/donottranslate-more-keys.xml24
-rw-r--r--java/res/values-sl/donottranslate-more-keys.xml25
-rw-r--r--java/res/values-sw600dp-land/dimens.xml1
-rw-r--r--java/res/values-sw600dp/config.xml1
-rw-r--r--java/res/values-sw600dp/dimens.xml1
-rw-r--r--java/res/values-sw768dp-land/dimens.xml1
-rw-r--r--java/res/values-sw768dp/config.xml1
-rw-r--r--java/res/values-sw768dp/dimens.xml1
-rw-r--r--java/res/values-uk/donottranslate-more-keys.xml23
-rw-r--r--java/res/values-vi/donottranslate-more-keys.xml28
-rw-r--r--java/res/values/attrs.xml44
-rw-r--r--java/res/values/config.xml1
-rw-r--r--java/res/values/dimens.xml1
-rw-r--r--java/res/values/donottranslate-more-keys.xml13
-rw-r--r--java/res/values/keyboard-icons-black.xml7
-rw-r--r--java/res/values/keyboard-icons-ics.xml9
-rw-r--r--java/res/values/keyboard-icons-white.xml8
-rw-r--r--java/res/values/styles.xml84
-rw-r--r--java/res/values/themes-basic-highcontrast.xml2
-rw-r--r--java/res/values/themes-basic.xml2
-rw-r--r--java/res/values/themes-gingerbread.xml2
-rw-r--r--java/res/values/themes-ics.xml2
-rw-r--r--java/res/values/themes-stone-bold.xml2
-rw-r--r--java/res/values/themes-stone.xml2
-rw-r--r--java/res/xml-be/keyboard_set.xml42
-rw-r--r--java/res/xml-ky/keyboard_set.xml42
-rw-r--r--java/res/xml-ro/keyboard_set.xml42
-rw-r--r--java/res/xml-ru/keyboard_set.xml2
-rw-r--r--java/res/xml-sk/keyboard_set.xml42
-rw-r--r--java/res/xml-sl/keyboard_set.xml42
-rw-r--r--java/res/xml-sw600dp/kbd_key_styles.xml2
-rw-r--r--java/res/xml-sw600dp/kbd_rows_slavic.xml (renamed from java/res/xml-sw600dp/kbd_rows_russian.xml)18
-rw-r--r--java/res/xml-sw768dp/kbd_key_styles.xml2
-rw-r--r--java/res/xml-sw768dp/kbd_rows_slavic.xml (renamed from java/res/xml-sw768dp/kbd_rows_russian.xml)18
-rw-r--r--java/res/xml-uk/keyboard_set.xml42
-rw-r--r--java/res/xml-vi/keyboard_set.xml42
-rw-r--r--java/res/xml/kbd_key_styles.xml2
-rw-r--r--java/res/xml/kbd_numkey_styles.xml2
-rw-r--r--java/res/xml/kbd_rows_slavic.xml (renamed from java/res/xml/kbd_rows_russian.xml)20
-rw-r--r--java/res/xml/kbd_slavic.xml (renamed from java/res/xml/kbd_russian.xml)2
-rw-r--r--java/res/xml/method.xml45
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java13
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java9
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java16
-rw-r--r--java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java1
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java7
-rw-r--r--java/src/com/android/inputmethod/compat/ArraysCompatUtils.java15
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java127
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyDetector.java37
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java1030
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java30
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSet.java178
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java142
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java115
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboard.java338
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java322
-rw-r--r--java/src/com/android/inputmethod/keyboard/MiniKeyboard.java8
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java3
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java121
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java833
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java109
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java190
-rw-r--r--java/src/com/android/inputmethod/latin/InputAttributes.java112
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java217
-rw-r--r--java/src/com/android/inputmethod/latin/LatinImeLogger.java1
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java21
-rw-r--r--java/src/com/android/inputmethod/latin/UserUnigramDictionary.java6
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java69
-rw-r--r--java/src/com/android/inputmethod/latin/XmlParseUtils.java (renamed from java/src/com/android/inputmethod/keyboard/internal/XmlParseUtils.java)6
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java (renamed from java/src/com/android/inputmethod/latin/MoreSuggestions.java)19
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java (renamed from java/src/com/android/inputmethod/latin/MoreSuggestionsView.java)3
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java (renamed from java/src/com/android/inputmethod/latin/SuggestionsView.java)26
80 files changed, 2700 insertions, 2180 deletions
diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 2e0cddc28..b9451f8ae 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -43,7 +43,7 @@
android:layout_width="@dimen/suggestions_strip_padding"
android:layout_height="@dimen/suggestions_strip_height"
style="?attr/suggestionsStripBackgroundStyle" />
- <com.android.inputmethod.latin.SuggestionsView
+ <com.android.inputmethod.latin.suggestions.SuggestionsView
android:id="@+id/suggestions_view"
android:layout_weight="1.0"
android:layout_width="0dp"
diff --git a/java/res/layout/more_suggestions.xml b/java/res/layout/more_suggestions.xml
index 6aa82e197..1e59b8931 100644
--- a/java/res/layout/more_suggestions.xml
+++ b/java/res/layout/more_suggestions.xml
@@ -24,7 +24,7 @@
android:orientation="horizontal"
style="?attr/miniKeyboardPanelStyle"
>
- <com.android.inputmethod.latin.MoreSuggestionsView
+ <com.android.inputmethod.latin.suggestions.MoreSuggestionsView
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/more_suggestions_view"
android:layout_alignParentBottom="true"
diff --git a/java/res/values-be/donottranslate-more-keys.xml b/java/res/values-be/donottranslate-more-keys.xml
new file mode 100644
index 000000000..28264c4ac
--- /dev/null
+++ b/java/res/values-be/donottranslate-more-keys.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keylabel_for_slavic_shcha">ў</string>
+ <string name="keylabel_for_slavic_i">i</string>
+</resources>
diff --git a/java/res/values-ky/donottranslate-more-keys.xml b/java/res/values-ky/donottranslate-more-keys.xml
new file mode 100644
index 000000000..d56cde577
--- /dev/null
+++ b/java/res/values-ky/donottranslate-more-keys.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="more_keys_for_slavic_u">3,ү</string>
+ <string name="more_keys_for_slavic_en">6,ң</string>
+ <string name="more_keys_for_slavic_o">ө</string>
+</resources>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index 4a5c5a44c..dcbfe463e 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -53,6 +53,7 @@
<fraction name="key_hint_label_ratio">52%</fraction>
<fraction name="key_uppercase_letter_ratio">40%</fraction>
<fraction name="key_preview_text_ratio">90%</fraction>
+ <fraction name="spacebar_text_ratio">40.000%</fraction>
<dimen name="key_preview_offset">0.08in</dimen>
<dimen name="key_preview_offset_ics">0.01in</dimen>
diff --git a/java/res/values-ro/donottranslate-more-keys.xml b/java/res/values-ro/donottranslate-more-keys.xml
index d7e6a171d..51df56099 100644
--- a/java/res/values-ro/donottranslate-more-keys.xml
+++ b/java/res/values-ro/donottranslate-more-keys.xml
@@ -18,7 +18,7 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="more_keys_for_a">ă,â,à,á,ä,æ,ã,å,ā</string>
+ <string name="more_keys_for_a">â,ã,ă,à,á,ä,æ,å,ā</string>
<string name="more_keys_for_i">8,î,ï,ì,í,į,ī</string>
<string name="more_keys_for_s">ș,ß,ś,š</string>
<string name="more_keys_for_t">5,ț</string>
diff --git a/java/res/values-ru/donottranslate-more-keys.xml b/java/res/values-ru/donottranslate-more-keys.xml
index f7e006e84..7ae9ffbda 100644
--- a/java/res/values-ru/donottranslate-more-keys.xml
+++ b/java/res/values-ru/donottranslate-more-keys.xml
@@ -18,7 +18,5 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="more_keys_for_cyrillic_e">5,ё</string>
- <string name="more_keys_for_cyrillic_soft_sign">ъ</string>
- <string name="more_keys_for_cyrillic_ha">ъ</string>
+ <string name="more_keys_for_slavic_ye">5,ё</string>
</resources>
diff --git a/java/res/values-sk/donottranslate-more-keys.xml b/java/res/values-sk/donottranslate-more-keys.xml
index b73db0a46..b6b35c1a3 100644
--- a/java/res/values-sk/donottranslate-more-keys.xml
+++ b/java/res/values-sk/donottranslate-more-keys.xml
@@ -18,18 +18,20 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="more_keys_for_a">ä,á,à,â,æ,ã,å,ā</string>
- <string name="more_keys_for_e">3,é,ě,è,ê,ë,ę,ė,ē</string>
- <string name="more_keys_for_i">8,í,î,ï,ì,į,ī</string>
- <string name="more_keys_for_o">9,ô,ó,ö,ò,õ,œ,ø,ō</string>
- <string name="more_keys_for_u">7,ú,ú,û,ü,ù,ū</string>
- <string name="more_keys_for_s">š,ß,ś</string>
- <string name="more_keys_for_n">ň,ñ,ń</string>
+ <string name="more_keys_for_a">á,ä,ā,à,â,ã,å,æ,ą</string>
+ <string name="more_keys_for_e">3,é,ě,ē,ė,è,ê,ë,ę</string>
+ <string name="more_keys_for_i">8,í,ī,į,ì,î,ï,ı</string>
+ <string name="more_keys_for_o">9,ô,ó,ö,ò,õ,œ,ő,ø</string>
+ <string name="more_keys_for_u">7,ú,ů,ü,ū,ų,ù,û,ű</string>
+ <string name="more_keys_for_s">š,ß,ś,ş</string>
+ <string name="more_keys_for_n">ň,ņ,ñ,ń,ń</string>
<string name="more_keys_for_c">č,ç,ć</string>
<string name="more_keys_for_y">6,ý,ÿ</string>
<string name="more_keys_for_d">ď</string>
- <string name="more_keys_for_r">4,ŕ,ř</string>
- <string name="more_keys_for_t">5,ť</string>
- <string name="more_keys_for_z">ž,ź,ż</string>
- <string name="more_keys_for_l">ľ,ĺ,ł</string>
+ <string name="more_keys_for_r">4,ŕ,ř,ŗ</string>
+ <string name="more_keys_for_t">5,ť,ţ</string>
+ <string name="more_keys_for_z">ž,ż,ź</string>
+ <string name="more_keys_for_k">ķ</string>
+ <string name="more_keys_for_l">ľ,ĺ,ļ,ł</string>
+ <string name="more_keys_for_g">ģ,ğ</string>
</resources>
diff --git a/java/res/values-sl/donottranslate-more-keys.xml b/java/res/values-sl/donottranslate-more-keys.xml
new file mode 100644
index 000000000..b72c6799e
--- /dev/null
+++ b/java/res/values-sl/donottranslate-more-keys.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="more_keys_for_s">š</string>
+ <string name="more_keys_for_c">č,ć</string>
+ <string name="more_keys_for_d">đ</string>
+ <string name="more_keys_for_z">ž</string>
+</resources>
diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml
index 1b8c8a64a..1c725a484 100644
--- a/java/res/values-sw600dp-land/dimens.xml
+++ b/java/res/values-sw600dp-land/dimens.xml
@@ -48,6 +48,7 @@
<fraction name="key_hint_letter_ratio">23%</fraction>
<fraction name="key_hint_label_ratio">34%</fraction>
<fraction name="key_uppercase_letter_ratio">29%</fraction>
+ <fraction name="spacebar_text_ratio">33.33%</fraction>
<dimen name="suggestions_strip_padding">40.0mm</dimen>
<integer name="max_more_suggestions_row">5</integer>
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml
index 1854a8696..1dd93121d 100644
--- a/java/res/values-sw600dp/config.xml
+++ b/java/res/values-sw600dp/config.xml
@@ -38,6 +38,5 @@
<integer name="config_long_press_space_key_timeout">0</integer>
<!-- 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_more_keys_column">5</integer>
</resources>
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml
index 31830239d..e393be579 100644
--- a/java/res/values-sw600dp/dimens.xml
+++ b/java/res/values-sw600dp/dimens.xml
@@ -59,6 +59,7 @@
<fraction name="key_hint_label_ratio">28%</fraction>
<fraction name="key_uppercase_letter_ratio">26%</fraction>
<fraction name="key_preview_text_ratio">50%</fraction>
+ <fraction name="spacebar_text_ratio">32.14%</fraction>
<dimen name="key_preview_height">15.0mm</dimen>
<dimen name="key_preview_offset">0.1in</dimen>
diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml
index 664e8c159..ef39f4393 100644
--- a/java/res/values-sw768dp-land/dimens.xml
+++ b/java/res/values-sw768dp-land/dimens.xml
@@ -52,6 +52,7 @@
<fraction name="key_hint_letter_ratio">23%</fraction>
<fraction name="key_hint_label_ratio">28%</fraction>
<fraction name="key_uppercase_letter_ratio">24%</fraction>
+ <fraction name="spacebar_text_ratio">24.00%</fraction>
<dimen name="key_preview_height">17.0mm</dimen>
<dimen name="key_preview_height_ics">26.5mm</dimen>
diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml
index c25139a42..06553a7c9 100644
--- a/java/res/values-sw768dp/config.xml
+++ b/java/res/values-sw768dp/config.xml
@@ -36,7 +36,6 @@
<integer name="config_long_press_space_key_timeout">0</integer>
<!-- 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_more_keys_column">5</integer>
<!-- Screen metrics for logging.
0 = "mdpi phone screen"
diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml
index bb4937dd5..dbbd844f0 100644
--- a/java/res/values-sw768dp/dimens.xml
+++ b/java/res/values-sw768dp/dimens.xml
@@ -62,6 +62,7 @@
<fraction name="key_hint_label_ratio">28%</fraction>
<fraction name="key_uppercase_letter_ratio">26%</fraction>
<fraction name="key_preview_text_ratio">50%</fraction>
+ <fraction name="spacebar_text_ratio">29.03%</fraction>
<dimen name="key_preview_height">15.0mm</dimen>
<dimen name="key_preview_offset">0.1in</dimen>
diff --git a/java/res/values-uk/donottranslate-more-keys.xml b/java/res/values-uk/donottranslate-more-keys.xml
new file mode 100644
index 000000000..4e7910128
--- /dev/null
+++ b/java/res/values-uk/donottranslate-more-keys.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="keylabel_for_slavic_yery">і</string>
+ <string name="more_keys_for_slavic_yery">ї</string>
+</resources>
diff --git a/java/res/values-vi/donottranslate-more-keys.xml b/java/res/values-vi/donottranslate-more-keys.xml
new file mode 100644
index 000000000..97a7d79ae
--- /dev/null
+++ b/java/res/values-vi/donottranslate-more-keys.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="more_keys_for_a">à,á,ả,ã,ạ,ă,ằ,ắ,ẳ,ẵ,ặ,â,ầ,ấ,ẩ,ẫ,ậ</string>
+ <string name="more_keys_for_e">3,è,é,ẻ,ẽ,ẹ,ê,ề,ế,ể,ễ,ệ</string>
+ <string name="more_keys_for_i">8,ì,í,ỉ,ĩ,ị</string>
+ <string name="more_keys_for_o">9,ò,ó,ỏ,õ,ọ,ô,ồ,ố,ổ,ỗ,ộ,ơ,ờ,ớ,ở,ỡ,ợ</string>
+ <string name="more_keys_for_u">7,ù,ú,ủ,ũ,ụ,ư,ừ,ứ,ử,ữ,ự</string>
+ <string name="more_keys_for_y">6,ỳ,ý,ỷ,ỹ,ỵ</string>
+ <string name="more_keys_for_d">đ</string>
+</resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 94f7ab78b..9892d7835 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -18,10 +18,13 @@
<declare-styleable name="KeyboardTheme">
<!-- Keyboard style -->
<attr name="keyboardStyle" format="reference" />
+ <!-- TODO: Get rid of latinKeyboardStyle -->
<!-- LatinKeyboard style -->
<attr name="latinKeyboardStyle" format="reference" />
<!-- KeyboardView style -->
<attr name="keyboardViewStyle" format="reference" />
+ <!-- LatinKeyboardView style -->
+ <attr name="latinKeyboardViewStyle" format="reference" />
<!-- MiniKeyboard style -->
<attr name="miniKeyboardStyle" format="reference" />
<!-- MiniKeyboardView style -->
@@ -120,6 +123,15 @@
</attr>
</declare-styleable>
+ <declare-styleable name="LatinKeyboardView">
+ <attr name="autoCorrectionSpacebarLedEnabled" format="boolean" />
+ <attr name="autoCorrectionSpacebarLedIcon" format="reference" />
+ <!-- Size of the text for spacebar language label, in the proportion of key height. -->
+ <attr name="spacebarTextRatio" format="fraction" />
+ <attr name="spacebarTextColor" format="color" />
+ <attr name="spacebarTextShadowColor" format="color" />
+ </declare-styleable>
+
<declare-styleable name="SuggestionsView">
<attr name="suggestionStripOption" format="integer">
<!-- This should be aligned with SuggestionsViewParams.AUTO_CORRECT_* and etc. -->
@@ -127,9 +139,11 @@
<flag name="autoCorrectUnderline" value="0x02" />
<flag name="validTypedWordBold" value="0x04" />
</attr>
+ <attr name="colorValidTypedWord" format="color" />
<attr name="colorTypedWord" format="color" />
<attr name="colorAutoCorrect" format="color" />
<attr name="colorSuggested" format="color" />
+ <attr name="alphaValidTypedWord" format="integer" />
<attr name="alphaTypedWord" format="integer" />
<attr name="alphaAutoCorrect" format="integer" />
<attr name="alphaSuggested" format="integer" />
@@ -176,7 +190,9 @@
<attr name="iconTabKey" format="reference" />
<attr name="iconShortcutKey" format="reference" />
<attr name="iconShortcutForLabel" format="reference" />
- <attr name="iconShiftedShiftKey" format="reference" />
+ <attr name="iconSpaceKeyForNumberLayout" format="reference" />
+ <attr name="iconShiftKeyShifted" format="reference" />
+ <attr name="iconDisabledShortcutKey" format="reference" />
<attr name="iconPreviewTabKey" format="reference" />
</declare-styleable>
@@ -229,26 +245,30 @@
</attr>
<!-- The icon to display on the key instead of the label. -->
<attr name="keyIcon" format="enum">
- <!-- This should be aligned with KeyboardIcons.ICON_* -->
+ <!-- This should be aligned with the KeyboardIcons.ICONS_TO_ATTRS_MAP -->
<enum name="iconShiftKey" value="1" />
<enum name="iconDeleteKey" value="2" />
+ <!-- This is also represented as "@icon/3" in keyboard layout XML. -->
<enum name="iconSettingsKey" value="3" />
<enum name="iconSpaceKey" value="4" />
<enum name="iconReturnKey" value="5" />
<enum name="iconSearchKey" value="6" />
+ <!-- This is also represented as "@icon/7" in keyboard layout XML. -->
<enum name="iconTabKey" value="7" />
<enum name="iconShortcutKey" value="8" />
<enum name="iconShortcutForLabel" value="9" />
+ <enum name="iconSpaceKeyForNumberLayout" value="10" />
+ <enum name="iconShiftKeyShifted" value="11" />
</attr>
- <!-- Shift key icon for shifted state -->
- <attr name="keyIconShifted" format="enum">
- <!-- This should be aligned with KeyboardIcons.ICON_SHIFTED_* -->
- <enum name="iconShiftedShiftKey" value="10" />
+ <!-- The icon for disabled key -->
+ <attr name="keyIconDisabled" format="enum">
+ <!-- This should be aligned with the KeyboardIcons.ICONS_TO_ATTRS_MAP -->
+ <enum name="iconDisabledShortcutKey" value="12" />
</attr>
<!-- The icon to show in the popup preview. -->
<attr name="keyIconPreview" format="enum">
- <!-- This should be aligned with KeyboardIcons.ICON_PREVIEW_* -->
- <enum name="iconPreviewTabKey" value="11" />
+ <!-- This should be aligned with the KeyboardIcons.ICONS_TO_ATTRS_MAP -->
+ <enum name="iconPreviewTabKey" value="13" />
</attr>
<!-- The key style to specify a set of key attributes defined by <key_style/> -->
<attr name="keyStyle" format="string" />
@@ -319,14 +339,6 @@
<attr name="parentStyle" format="string" />
</declare-styleable>
- <declare-styleable name="LatinKeyboard">
- <attr name="autoCorrectionSpacebarLedEnabled" format="boolean" />
- <attr name="autoCorrectionSpacebarLedIcon" format="reference" />
- <attr name="disabledShortcutIcon" format="reference" />
- <attr name="spacebarTextColor" format="color" />
- <attr name="spacebarTextShadowColor" format="color" />
- </declare-styleable>
-
<declare-styleable name="KeyboardSet">
<!-- Locale of the keyboard layouts -->
<attr name="keyboardLocale" format="string" />
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index 8b99a1fcb..55f35f0c5 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -66,7 +66,6 @@
<dimen name="config_touch_noise_threshold_distance">2.0mm</dimen>
<!-- 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">small</string>
<integer name="config_max_more_keys_column">5</integer>
<string-array name="auto_correction_threshold_values" translatable="false">
<!-- Off, When auto correction setting is Off, this value is not used. -->
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 352141ca6..e46ff7718 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -66,6 +66,7 @@
<fraction name="key_hint_label_ratio">44%</fraction>
<fraction name="key_uppercase_letter_ratio">35%</fraction>
<fraction name="key_preview_text_ratio">82%</fraction>
+ <fraction name="spacebar_text_ratio">33.735%</fraction>
<dimen name="key_preview_height">80sp</dimen>
<dimen name="key_preview_offset">0.1in</dimen>
diff --git a/java/res/values/donottranslate-more-keys.xml b/java/res/values/donottranslate-more-keys.xml
index 6c7753999..ac175dfe7 100644
--- a/java/res/values/donottranslate-more-keys.xml
+++ b/java/res/values/donottranslate-more-keys.xml
@@ -42,9 +42,16 @@
<string name="keylabel_for_scandinavia_row2_11"></string>
<string name="more_keys_for_scandinavia_row2_10"></string>
<string name="more_keys_for_scandinavia_row2_11"></string>
- <string name="more_keys_for_cyrillic_e"></string>
- <string name="more_keys_for_cyrillic_soft_sign"></string>
- <string name="more_keys_for_cyrillic_ha"></string>
+ <string name="keylabel_for_slavic_shcha">щ</string>
+ <string name="keylabel_for_slavic_yery">ы</string>
+ <string name="keylabel_for_slavic_i">и</string>
+ <string name="more_keys_for_slavic_u">3</string>
+ <string name="more_keys_for_slavic_ye">5</string>
+ <string name="more_keys_for_slavic_en">6</string>
+ <string name="more_keys_for_slavic_ha">ъ</string>
+ <string name="more_keys_for_slavic_yery"></string>
+ <string name="more_keys_for_slavic_o"></string>
+ <string name="more_keys_for_slavic_soft_sign">ъ</string>
<string name="more_keys_for_currency_dollar">¢,£,€,¥,₱</string>
<string name="more_keys_for_currency_euro">¢,£,$,¥,₱</string>
<string name="more_keys_for_currency_pound">¢,$,€,¥,₱</string>
diff --git a/java/res/values/keyboard-icons-black.xml b/java/res/values/keyboard-icons-black.xml
index f767cb349..1c5a5f720 100644
--- a/java/res/values/keyboard-icons-black.xml
+++ b/java/res/values/keyboard-icons-black.xml
@@ -30,10 +30,9 @@
<item name="iconTabKey">@drawable/sym_bkeyboard_tab</item>
<item name="iconShortcutKey">@drawable/sym_bkeyboard_mic</item>
<item name="iconShortcutForLabel">@drawable/sym_bkeyboard_label_mic</item>
- <item name="iconShiftedShiftKey">@drawable/sym_bkeyboard_shift_locked</item>
+ <item name="iconSpaceKeyForNumberLayout">@drawable/sym_bkeyboard_space</item>
+ <item name="iconShiftKeyShifted">@drawable/sym_bkeyboard_shift_locked</item>
+ <item name="iconDisabledShortcutKey">@drawable/sym_bkeyboard_voice_off</item>
<item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item>
- <!-- LatinKeyboard icons -->
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
- <item name="disabledShortcutIcon">@drawable/sym_bkeyboard_voice_off</item>
</style>
</resources>
diff --git a/java/res/values/keyboard-icons-ics.xml b/java/res/values/keyboard-icons-ics.xml
index f1021433d..f68be5f1e 100644
--- a/java/res/values/keyboard-icons-ics.xml
+++ b/java/res/values/keyboard-icons-ics.xml
@@ -23,16 +23,15 @@
<item name="iconShiftKey">@drawable/sym_keyboard_shift_holo</item>
<item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo</item>
<item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo</item>
- <item name="iconSpaceKey">@drawable/sym_keyboard_space_holo</item>
+ <item name="iconSpaceKey">@null</item>
<item name="iconReturnKey">@drawable/sym_keyboard_return_holo</item>
<item name="iconSearchKey">@drawable/sym_keyboard_search_holo</item>
<item name="iconTabKey">@drawable/sym_keyboard_tab_holo</item>
<item name="iconShortcutKey">@drawable/sym_keyboard_voice_holo</item>
<item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic_holo</item>
- <item name="iconShiftedShiftKey">@drawable/sym_keyboard_shift_locked_holo</item>
+ <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo</item>
+ <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo</item>
+ <item name="iconDisabledShortcutKey">@drawable/sym_keyboard_voice_off_holo</item>
<item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item>
- <!-- LatinKeyboard icons -->
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item>
- <item name="disabledShortcutIcon">@drawable/sym_keyboard_voice_off_holo</item>
</style>
</resources>
diff --git a/java/res/values/keyboard-icons-white.xml b/java/res/values/keyboard-icons-white.xml
index 07ece66b1..35197a1c0 100644
--- a/java/res/values/keyboard-icons-white.xml
+++ b/java/res/values/keyboard-icons-white.xml
@@ -26,10 +26,10 @@
<item name="iconTabKey">@drawable/sym_keyboard_tab</item>
<item name="iconShortcutKey">@drawable/sym_keyboard_mic</item>
<item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic</item>
- <item name="iconShiftedShiftKey">@drawable/sym_keyboard_shift_locked</item>
+ <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space</item>
+ <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked</item>
+ <!-- TODO: Needs non-holo disabled shortcut icon drawable -->
+ <item name="iconDisabledShortcutKey">@drawable/sym_keyboard_voice_off_holo</item>
<item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item>
- <!-- LatinKeyboard icons -->
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
- <item name="disabledShortcutIcon">@drawable/sym_keyboard_voice_off_holo</item>
</style>
</resources>
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 2b5fb08e5..c4e39e357 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -31,11 +31,6 @@
<item name="verticalGap">@fraction/key_bottom_gap</item>
<item name="maxMoreKeysColumn">@integer/config_max_more_keys_column</item>
</style>
- <style name="LatinKeyboard">
- <item name="autoCorrectionSpacebarLedEnabled">true</item>
- <item name="spacebarTextColor">#FFC0C0C0</item>
- <item name="spacebarTextShadowColor">#80000000</item>
- </style>
<style name="KeyboardView">
<item name="android:background">@drawable/keyboard_background</item>
<item name="keyBackground">@drawable/btn_keyboard_key</item>
@@ -71,6 +66,15 @@
<item name="backgroundDimAmount">0.5</item>
</style>
<style
+ name="LatinKeyboardView"
+ parent="KeyboardView">
+ <item name="autoCorrectionSpacebarLedEnabled">true</item>
+ <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
+ <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
+ <item name="spacebarTextColor">#FFC0C0C0</item>
+ <item name="spacebarTextShadowColor">#80000000</item>
+ </style>
+ <style
name="MiniKeyboard"
parent="Keyboard"
>
@@ -97,7 +101,8 @@
name="SuggestionsViewStyle"
parent="SuggestionsStripBackgroundStyle"
>
- <item name="suggestionStripOption">autoCorrectBold</item>
+ <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item>
+ <item name="colorValidTypedWord">#FFFCAE00</item>
<item name="colorTypedWord">@android:color/white</item>
<item name="colorAutoCorrect">#FFFCAE00</item>
<item name="colorSuggested">#FFFCAE00</item>
@@ -132,6 +137,16 @@
<item name="android:background">@android:color/black</item>
<item name="keyBackground">@drawable/btn_keyboard_key3</item>
</style>
+ <style
+ name="LatinKeyboardView.HighContrast"
+ parent="KeyboardView.HighContrast"
+ >
+ <item name="autoCorrectionSpacebarLedEnabled">true</item>
+ <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
+ <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
+ <item name="spacebarTextColor">#FFC0C0C0</item>
+ <item name="spacebarTextShadowColor">#80000000</item>
+ </style>
<!-- Theme "Stone" -->
<style
name="Keyboard.Stone"
@@ -145,13 +160,6 @@
<item name="verticalGap">@fraction/key_bottom_gap_stone</item>
</style>
<style
- name="LatinKeyboard.Stone"
- parent="LatinKeyboard"
- >
- <item name="spacebarTextColor">#FF000000</item>
- <item name="spacebarTextShadowColor">#D0FFFFFF</item>
- </style>
- <style
name="KeyboardView.Stone"
parent="KeyboardView"
>
@@ -165,6 +173,16 @@
<item name="shadowColor">#FFFFFFFF</item>
</style>
<style
+ name="LatinKeyboardView.Stone"
+ parent="KeyboardView.Stone"
+ >
+ <item name="autoCorrectionSpacebarLedEnabled">true</item>
+ <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
+ <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
+ <item name="spacebarTextColor">#FF000000</item>
+ <item name="spacebarTextShadowColor">#D0FFFFFF</item>
+ </style>
+ <style
name="MiniKeyboard.Stone"
parent="Keyboard.Stone"
>
@@ -193,6 +211,16 @@
>
<item name="keyTextStyle">bold</item>
</style>
+ <style
+ name="LatinKeyboardView.Stone.Bold"
+ parent="KeyboardView.Stone.Bold"
+ >
+ <item name="autoCorrectionSpacebarLedEnabled">true</item>
+ <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
+ <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
+ <item name="spacebarTextColor">#FF000000</item>
+ <item name="spacebarTextShadowColor">#D0FFFFFF</item>
+ </style>
<!-- Theme "Gingerbread" -->
<style
name="Keyboard.Gingerbread"
@@ -212,6 +240,16 @@
<item name="keyTextStyle">bold</item>
</style>
<style
+ name="LatinKeyboardView.Gingerbread"
+ parent="KeyboardView.Gingerbread"
+ >
+ <item name="autoCorrectionSpacebarLedEnabled">true</item>
+ <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
+ <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
+ <item name="spacebarTextColor">#FFC0C0C0</item>
+ <item name="spacebarTextShadowColor">#80000000</item>
+ </style>
+ <style
name="MiniKeyboard.Gingerbread"
parent="Keyboard.Gingerbread"
>
@@ -238,13 +276,6 @@
<item name="touchPositionCorrectionData">@array/touch_position_correction_data_ice_cream_sandwich</item>
</style>
<style
- name="LatinKeyboard.IceCreamSandwich"
- parent="LatinKeyboard"
- >
- <item name="autoCorrectionSpacebarLedEnabled">false</item>
- <item name="disabledShortcutIcon">@drawable/sym_keyboard_voice_off_holo</item>
- </style>
- <style
name="KeyboardView.IceCreamSandwich"
parent="KeyboardView"
>
@@ -268,6 +299,16 @@
<item name="shadowRadius">0.0</item>
</style>
<style
+ name="LatinKeyboardView.IceCreamSandwich"
+ parent="KeyboardView.IceCreamSandwich"
+ >
+ <item name="autoCorrectionSpacebarLedEnabled">false</item>
+ <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item>
+ <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
+ <item name="spacebarTextColor">#FFC0C0C0</item>
+ <item name="spacebarTextShadowColor">#80000000</item>
+ </style>
+ <style
name="MiniKeyboard.IceCreamSandwich"
parent="Keyboard.IceCreamSandwich"
>
@@ -296,11 +337,12 @@
>
<item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item>
<!-- android:color/holo_blue_light=#FF33B5E5 -->
+ <item name="colorValidTypedWord">@android:color/holo_blue_light</item>
<item name="colorTypedWord">@android:color/holo_blue_light</item>
<item name="colorAutoCorrect">@android:color/holo_blue_light</item>
<item name="colorSuggested">@android:color/holo_blue_light</item>
+ <item name="alphaValidTypedWord">85</item>
<item name="alphaTypedWord">85</item>
- <item name="alphaAutoCorrect">100</item>
<item name="alphaSuggested">70</item>
<item name="alphaObsoleted">70</item>
<item name="suggestionsCountInStrip">@integer/suggestions_count_in_strip</item>
diff --git a/java/res/values/themes-basic-highcontrast.xml b/java/res/values/themes-basic-highcontrast.xml
index abb7c8057..0062b2837 100644
--- a/java/res/values/themes-basic-highcontrast.xml
+++ b/java/res/values/themes-basic-highcontrast.xml
@@ -17,8 +17,8 @@
<resources>
<style name="KeyboardTheme.HighContrast" parent="KeyboardIcons">
<item name="keyboardStyle">@style/Keyboard.HighContrast</item>
- <item name="latinKeyboardStyle">@style/LatinKeyboard</item>
<item name="keyboardViewStyle">@style/KeyboardView.HighContrast</item>
+ <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.HighContrast</item>
<item name="miniKeyboardStyle">@style/MiniKeyboard</item>
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item>
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
diff --git a/java/res/values/themes-basic.xml b/java/res/values/themes-basic.xml
index ff9fed55f..0786e08fc 100644
--- a/java/res/values/themes-basic.xml
+++ b/java/res/values/themes-basic.xml
@@ -17,8 +17,8 @@
<resources>
<style name="KeyboardTheme" parent="KeyboardIcons">
<item name="keyboardStyle">@style/Keyboard</item>
- <item name="latinKeyboardStyle">@style/LatinKeyboard</item>
<item name="keyboardViewStyle">@style/KeyboardView</item>
+ <item name="latinKeyboardViewStyle">@style/LatinKeyboardView</item>
<item name="miniKeyboardStyle">@style/MiniKeyboard</item>
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item>
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
diff --git a/java/res/values/themes-gingerbread.xml b/java/res/values/themes-gingerbread.xml
index be853eb0f..44338d821 100644
--- a/java/res/values/themes-gingerbread.xml
+++ b/java/res/values/themes-gingerbread.xml
@@ -17,8 +17,8 @@
<resources>
<style name="KeyboardTheme.Gingerbread" parent="KeyboardIcons">
<item name="keyboardStyle">@style/Keyboard.Gingerbread</item>
- <item name="latinKeyboardStyle">@style/LatinKeyboard</item>
<item name="keyboardViewStyle">@style/KeyboardView.Gingerbread</item>
+ <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.Gingerbread</item>
<item name="miniKeyboardStyle">@style/MiniKeyboard.Gingerbread</item>
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Gingerbread</item>
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index 618aaed79..dbc8f32e3 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -17,8 +17,8 @@
<resources>
<style name="KeyboardTheme.IceCreamSandwich" parent="KeyboardIcons.IceCreamSandwich">
<item name="keyboardStyle">@style/Keyboard.IceCreamSandwich</item>
- <item name="latinKeyboardStyle">@style/LatinKeyboard.IceCreamSandwich</item>
<item name="keyboardViewStyle">@style/KeyboardView.IceCreamSandwich</item>
+ <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.IceCreamSandwich</item>
<item name="miniKeyboardStyle">@style/MiniKeyboard.IceCreamSandwich</item>
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView.IceCreamSandwich</item>
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle.IceCreamSandwich</item>
diff --git a/java/res/values/themes-stone-bold.xml b/java/res/values/themes-stone-bold.xml
index 532a2985e..60f130d59 100644
--- a/java/res/values/themes-stone-bold.xml
+++ b/java/res/values/themes-stone-bold.xml
@@ -17,8 +17,8 @@
<resources>
<style name="KeyboardTheme.Stone.Bold" parent="KeyboardIcons.Black">
<item name="keyboardStyle">@style/Keyboard.Stone.Bold</item>
- <item name="latinKeyboardStyle">@style/LatinKeyboard.Stone</item>
<item name="keyboardViewStyle">@style/KeyboardView.Stone.Bold</item>
+ <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.Stone.Bold</item>
<item name="miniKeyboardStyle">@style/MiniKeyboard.Stone</item>
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item>
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
diff --git a/java/res/values/themes-stone.xml b/java/res/values/themes-stone.xml
index cb3edc58f..9aaca3a6c 100644
--- a/java/res/values/themes-stone.xml
+++ b/java/res/values/themes-stone.xml
@@ -17,8 +17,8 @@
<resources>
<style name="KeyboardTheme.Stone" parent="KeyboardIcons.Black">
<item name="keyboardStyle">@style/Keyboard.Stone</item>
- <item name="latinKeyboardStyle">@style/LatinKeyboard.Stone</item>
<item name="keyboardViewStyle">@style/KeyboardView.Stone</item>
+ <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.Stone</item>
<item name="miniKeyboardStyle">@style/MiniKeyboard.Stone</item>
<item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item>
<item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
diff --git a/java/res/xml-be/keyboard_set.xml b/java/res/xml-be/keyboard_set.xml
new file mode 100644
index 000000000..e5c6ba35a
--- /dev/null
+++ b/java/res/xml-be/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyboardLocale="be">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_slavic" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShift"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneShift"
+ latin:elementKeyboard="@xml/kbd_phone_shift" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml-ky/keyboard_set.xml b/java/res/xml-ky/keyboard_set.xml
new file mode 100644
index 000000000..7cdd0a169
--- /dev/null
+++ b/java/res/xml-ky/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyboardLocale="ky">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_slavic" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShift"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneShift"
+ latin:elementKeyboard="@xml/kbd_phone_shift" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml-ro/keyboard_set.xml b/java/res/xml-ro/keyboard_set.xml
new file mode 100644
index 000000000..725cb52d2
--- /dev/null
+++ b/java/res/xml-ro/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyboardLocale="ro">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_qwerty" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShift"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneShift"
+ latin:elementKeyboard="@xml/kbd_phone_shift" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml-ru/keyboard_set.xml b/java/res/xml-ru/keyboard_set.xml
index eabee5dc3..0a158d9cc 100644
--- a/java/res/xml-ru/keyboard_set.xml
+++ b/java/res/xml-ru/keyboard_set.xml
@@ -23,7 +23,7 @@
latin:keyboardLocale="ru">
<Element
latin:elementName="alphabet"
- latin:elementKeyboard="@xml/kbd_russian" />
+ latin:elementKeyboard="@xml/kbd_slavic" />
<Element
latin:elementName="symbols"
latin:elementKeyboard="@xml/kbd_symbols" />
diff --git a/java/res/xml-sk/keyboard_set.xml b/java/res/xml-sk/keyboard_set.xml
new file mode 100644
index 000000000..9df01dda6
--- /dev/null
+++ b/java/res/xml-sk/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyboardLocale="sk">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_qwerty" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShift"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneShift"
+ latin:elementKeyboard="@xml/kbd_phone_shift" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml-sl/keyboard_set.xml b/java/res/xml-sl/keyboard_set.xml
new file mode 100644
index 000000000..d2ec4c02d
--- /dev/null
+++ b/java/res/xml-sl/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyboardLocale="sl">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_qwerty" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShift"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneShift"
+ latin:elementKeyboard="@xml/kbd_phone_shift" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml-sw600dp/kbd_key_styles.xml b/java/res/xml-sw600dp/kbd_key_styles.xml
index e0171b030..1dd0307c7 100644
--- a/java/res/xml-sw600dp/kbd_key_styles.xml
+++ b/java/res/xml-sw600dp/kbd_key_styles.xml
@@ -43,7 +43,6 @@
latin:styleName="shiftKeyStyle"
latin:code="@integer/key_shift"
latin:keyIcon="iconShiftKey"
- latin:keyIconShifted="iconShiftedShiftKey"
latin:keyActionFlags="noKeyPreview"
latin:backgroundType="sticky" />
<key-style
@@ -77,6 +76,7 @@
latin:styleName="shortcutKeyStyle"
latin:code="@integer/key_shortcut"
latin:keyIcon="iconShortcutKey"
+ latin:keyIconDisabled="iconDisabledShortcutKey"
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
latin:altCode="@integer/key_dummy"
latin:parentStyle="f2PopupStyle" />
diff --git a/java/res/xml-sw600dp/kbd_rows_russian.xml b/java/res/xml-sw600dp/kbd_rows_slavic.xml
index 3395065ed..0a162058d 100644
--- a/java/res/xml-sw600dp/kbd_rows_russian.xml
+++ b/java/res/xml-sw600dp/kbd_rows_slavic.xml
@@ -31,20 +31,22 @@
<Key
latin:keyLabel="ц" />
<Key
- latin:keyLabel="у" />
+ latin:keyLabel="у"
+ latin:moreKeys="@string/more_keys_for_slavic_u" />
<Key
latin:keyLabel="к" />
<Key
latin:keyLabel="е"
- latin:moreKeys="@string/more_keys_for_cyrillic_e" />
+ latin:moreKeys="@string/more_keys_for_slavic_ye" />
<Key
- latin:keyLabel="н" />
+ latin:keyLabel="н"
+ latin:moreKeys="@string/more_keys_for_slavic_en" />
<Key
latin:keyLabel="г" />
<Key
latin:keyLabel="ш" />
<Key
- latin:keyLabel="щ" />
+ latin:keyLabel="@string/keylabel_for_slavic_shcha" />
<Key
latin:keyLabel="з" />
<Key
@@ -63,7 +65,8 @@
latin:keyLabel="ф"
latin:keyXPos="2.25%p" />
<Key
- latin:keyLabel="ы" />
+ latin:keyLabel="@string/keylabel_for_slavic_yery"
+ latin:moreKeys="@string/more_keys_for_slavic_yery" />
<Key
latin:keyLabel="в" />
<Key
@@ -73,7 +76,8 @@
<Key
latin:keyLabel="р" />
<Key
- latin:keyLabel="о" />
+ latin:keyLabel="о"
+ latin:moreKeys="@string/more_keys_for_slavic_o" />
<Key
latin:keyLabel="л" />
<Key
@@ -101,7 +105,7 @@
<Key
latin:keyLabel="м" />
<Key
- latin:keyLabel="и" />
+ latin:keyLabel="@string/keylabel_for_slavic_i" />
<Key
latin:keyLabel="т" />
<Key
diff --git a/java/res/xml-sw768dp/kbd_key_styles.xml b/java/res/xml-sw768dp/kbd_key_styles.xml
index d9266508e..7292fe169 100644
--- a/java/res/xml-sw768dp/kbd_key_styles.xml
+++ b/java/res/xml-sw768dp/kbd_key_styles.xml
@@ -25,7 +25,6 @@
latin:styleName="shiftKeyStyle"
latin:code="@integer/key_shift"
latin:keyIcon="iconShiftKey"
- latin:keyIconShifted="iconShiftedShiftKey"
latin:keyActionFlags="noKeyPreview"
latin:backgroundType="sticky" />
<key-style
@@ -59,6 +58,7 @@
latin:styleName="shortcutKeyStyle"
latin:code="@integer/key_shortcut"
latin:keyIcon="iconShortcutKey"
+ latin:keyIconDisabled="iconDisabledShortcutKey"
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
latin:altCode="@integer/key_dummy"
latin:backgroundType="functional" />
diff --git a/java/res/xml-sw768dp/kbd_rows_russian.xml b/java/res/xml-sw768dp/kbd_rows_slavic.xml
index eb0baf95d..4c9128d86 100644
--- a/java/res/xml-sw768dp/kbd_rows_russian.xml
+++ b/java/res/xml-sw768dp/kbd_rows_slavic.xml
@@ -34,20 +34,22 @@
<Key
latin:keyLabel="ц" />
<Key
- latin:keyLabel="у" />
+ latin:keyLabel="у"
+ latin:moreKeys="@string/more_keys_for_slavic_u" />
<Key
latin:keyLabel="к" />
<Key
latin:keyLabel="е"
- latin:moreKeys="@string/more_keys_for_cyrillic_e" />
+ latin:moreKeys="@string/more_keys_for_slavic_ye" />
<Key
- latin:keyLabel="н" />
+ latin:keyLabel="н"
+ latin:moreKeys="@string/more_keys_for_slavic_en" />
<Key
latin:keyLabel="г" />
<Key
latin:keyLabel="ш" />
<Key
- latin:keyLabel="щ" />
+ latin:keyLabel="@string/keylabel_for_slavic_shcha" />
<Key
latin:keyLabel="з" />
<Key
@@ -68,7 +70,8 @@
<Key
latin:keyLabel="ф" />
<Key
- latin:keyLabel="ы" />
+ latin:keyLabel="@string/keylabel_for_slavic_yery"
+ latin:moreKeys="@string/more_keys_for_slavic_yery" />
<Key
latin:keyLabel="в" />
<Key
@@ -78,7 +81,8 @@
<Key
latin:keyLabel="р" />
<Key
- latin:keyLabel="о" />
+ latin:keyLabel="о"
+ latin:moreKeys="@string/more_keys_for_slavic_o" />
<Key
latin:keyLabel="л" />
<Key
@@ -107,7 +111,7 @@
<Key
latin:keyLabel="м" />
<Key
- latin:keyLabel="и" />
+ latin:keyLabel="@string/keylabel_for_slavic_i" />
<Key
latin:keyLabel="т" />
<Key
diff --git a/java/res/xml-uk/keyboard_set.xml b/java/res/xml-uk/keyboard_set.xml
new file mode 100644
index 000000000..e5ba43b23
--- /dev/null
+++ b/java/res/xml-uk/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyboardLocale="uk">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_slavic" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShift"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneShift"
+ latin:elementKeyboard="@xml/kbd_phone_shift" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml-vi/keyboard_set.xml b/java/res/xml-vi/keyboard_set.xml
new file mode 100644
index 000000000..7f4b25d9d
--- /dev/null
+++ b/java/res/xml-vi/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyboardLocale="vi">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_qwerty" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShift"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneShift"
+ latin:elementKeyboard="@xml/kbd_phone_shift" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml/kbd_key_styles.xml b/java/res/xml/kbd_key_styles.xml
index 5714e09c5..7869d21d0 100644
--- a/java/res/xml/kbd_key_styles.xml
+++ b/java/res/xml/kbd_key_styles.xml
@@ -66,7 +66,6 @@
latin:styleName="shiftKeyStyle"
latin:code="@integer/key_shift"
latin:keyIcon="iconShiftKey"
- latin:keyIconShifted="iconShiftedShiftKey"
latin:keyActionFlags="noKeyPreview"
latin:backgroundType="sticky" />
<key-style
@@ -163,6 +162,7 @@
latin:styleName="shortcutKeyStyle"
latin:code="@integer/key_shortcut"
latin:keyIcon="iconShortcutKey"
+ latin:keyIconDisabled="iconDisabledShortcutKey"
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
latin:altCode="@integer/key_space"
latin:parentStyle="f1PopupStyle" />
diff --git a/java/res/xml/kbd_numkey_styles.xml b/java/res/xml/kbd_numkey_styles.xml
index c2ff4d50f..003165da8 100644
--- a/java/res/xml/kbd_numkey_styles.xml
+++ b/java/res/xml/kbd_numkey_styles.xml
@@ -124,6 +124,6 @@
<key-style
latin:styleName="numSpaceKeyStyle"
latin:code="@integer/key_space"
- latin:keyIcon="iconSpaceKey"
+ latin:keyIcon="iconSpaceKeyForNumberLayout"
latin:parentStyle="numKeyBaseStyle" />
</merge>
diff --git a/java/res/xml/kbd_rows_russian.xml b/java/res/xml/kbd_rows_slavic.xml
index f1794e750..6536eaeb3 100644
--- a/java/res/xml/kbd_rows_russian.xml
+++ b/java/res/xml/kbd_rows_slavic.xml
@@ -37,7 +37,7 @@
<Key
latin:keyLabel="у"
latin:keyHintLabel="3"
- latin:moreKeys="3" />
+ latin:moreKeys="@string/more_keys_for_slavic_u" />
<Key
latin:keyLabel="к"
latin:keyHintLabel="4"
@@ -45,11 +45,11 @@
<Key
latin:keyLabel="е"
latin:keyHintLabel="5"
- latin:moreKeys="@string/more_keys_for_cyrillic_e" />
+ latin:moreKeys="@string/more_keys_for_slavic_ye" />
<Key
latin:keyLabel="н"
latin:keyHintLabel="6"
- latin:moreKeys="6" />
+ latin:moreKeys="@string/more_keys_for_slavic_en" />
<Key
latin:keyLabel="г"
latin:keyHintLabel="7"
@@ -59,7 +59,7 @@
latin:keyHintLabel="8"
latin:moreKeys="8" />
<Key
- latin:keyLabel="щ"
+ latin:keyLabel="@string/keylabel_for_slavic_shcha"
latin:keyHintLabel="9"
latin:moreKeys="9" />
<Key
@@ -68,7 +68,7 @@
latin:moreKeys="0" />
<Key
latin:keyLabel="х"
- latin:moreKeys="@string/more_keys_for_cyrillic_ha"
+ latin:moreKeys="@string/more_keys_for_slavic_ha"
latin:keyWidth="fillRight" />
</Row>
<Row
@@ -78,7 +78,8 @@
latin:keyLabel="ф"
latin:keyWidth="8.75%p" />
<Key
- latin:keyLabel="ы" />
+ latin:keyLabel="@string/keylabel_for_slavic_yery"
+ latin:moreKeys="@string/more_keys_for_slavic_yery" />
<Key
latin:keyLabel="в" />
<Key
@@ -88,7 +89,8 @@
<Key
latin:keyLabel="р" />
<Key
- latin:keyLabel="о" />
+ latin:keyLabel="о"
+ latin:moreKeys="@string/more_keys_for_slavic_o" />
<Key
latin:keyLabel="л" />
<Key
@@ -114,12 +116,12 @@
<Key
latin:keyLabel="м" />
<Key
- latin:keyLabel="и" />
+ latin:keyLabel="@string/keylabel_for_slavic_i" />
<Key
latin:keyLabel="т" />
<Key
latin:keyLabel="ь"
- latin:moreKeys="@string/more_keys_for_cyrillic_soft_sign" />
+ latin:moreKeys="@string/more_keys_for_slavic_soft_sign" />
<Key
latin:keyLabel="б" />
<Key
diff --git a/java/res/xml/kbd_russian.xml b/java/res/xml/kbd_slavic.xml
index 071bfd588..6207d2939 100644
--- a/java/res/xml/kbd_russian.xml
+++ b/java/res/xml/kbd_slavic.xml
@@ -22,5 +22,5 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<include
- latin:keyboardLayout="@xml/kbd_rows_russian" />
+ latin:keyboardLayout="@xml/kbd_rows_slavic" />
</Keyboard>
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 2b2c00c17..f58ad76f7 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -20,7 +20,8 @@
<!-- The attributes in this XML file provide configuration information -->
<!-- for the Input Method Manager. -->
-<!-- Keyboard: en_US, en_GB, ar, cs, da, de, de(QWERTY), es, es_US, et, fi, fr, fr_CA, fr_CH, hr, hu, it, iw, lt, lv, nb, nl, pl, pt, ru, sr, sv, tr -->
+<!-- Keyboard: en_US, en_GB, ar, be, cs, da, de, de(QWERTY), es, es_US, et, fi, fr, fr_CA, fr_CH,
+ hr, hu, it, iw, ky, lt, lv, nb, nl, pl, pt, ro, ru, sk, sl, sr, sv, tr, uk, vi -->
<!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. -->
<!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default
subtype.-->
@@ -47,6 +48,12 @@
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
+ android:imeSubtypeLocale="be"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
android:imeSubtypeLocale="cs"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
@@ -132,6 +139,12 @@
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
+ android:imeSubtypeLocale="ky"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
android:imeSubtypeLocale="lt"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
@@ -168,12 +181,30 @@
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
+ android:imeSubtypeLocale="ro"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
android:imeSubtypeLocale="ru"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
+ android:imeSubtypeLocale="sk"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
+ android:imeSubtypeLocale="sl"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
android:imeSubtypeLocale="sr"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
@@ -190,4 +221,16 @@
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
/>
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
+ android:imeSubtypeLocale="uk"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
+ android:imeSubtypeLocale="vi"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ />
</input-method>
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index 1836f27b3..9caed00c9 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -17,7 +17,6 @@
package com.android.inputmethod.accessibility;
import android.content.Context;
-import android.content.SharedPreferences;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
import android.os.SystemClock;
@@ -55,15 +54,15 @@ public class AccessibilityUtils {
*/
private static final boolean ENABLE_ACCESSIBILITY = true;
- public static void init(InputMethodService inputMethod, SharedPreferences prefs) {
+ public static void init(InputMethodService inputMethod) {
if (!ENABLE_ACCESSIBILITY)
return;
// These only need to be initialized if the kill switch is off.
- sInstance.initInternal(inputMethod, prefs);
- KeyCodeDescriptionMapper.init(inputMethod, prefs);
- AccessibleInputMethodServiceProxy.init(inputMethod, prefs);
- AccessibleKeyboardViewProxy.init(inputMethod, prefs);
+ sInstance.initInternal(inputMethod);
+ KeyCodeDescriptionMapper.init();
+ AccessibleInputMethodServiceProxy.init(inputMethod);
+ AccessibleKeyboardViewProxy.init(inputMethod);
}
public static AccessibilityUtils getInstance() {
@@ -74,7 +73,7 @@ public class AccessibilityUtils {
// This class is not publicly instantiable.
}
- private void initInternal(Context context, SharedPreferences prefs) {
+ private void initInternal(Context context) {
mContext = context;
mAccessibilityManager = (AccessibilityManager) context
.getSystemService(Context.ACCESSIBILITY_SERVICE);
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
index 4ab9cb898..d834dd10b 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
@@ -17,7 +17,6 @@
package com.android.inputmethod.accessibility;
import android.content.Context;
-import android.content.SharedPreferences;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
import android.os.Looper;
@@ -82,8 +81,8 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi
}
}
- public static void init(InputMethodService inputMethod, SharedPreferences prefs) {
- sInstance.initInternal(inputMethod, prefs);
+ public static void init(InputMethodService inputMethod) {
+ sInstance.initInternal(inputMethod);
}
public static AccessibleInputMethodServiceProxy getInstance() {
@@ -94,7 +93,7 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi
// Not publicly instantiable.
}
- private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) {
+ private void initInternal(InputMethodService inputMethod) {
mInputMethod = inputMethod;
mVibrator = (Vibrator) inputMethod.getSystemService(Context.VIBRATOR_SERVICE);
mAudioManager = (AudioManager) inputMethod.getSystemService(Context.AUDIO_SERVICE);
@@ -125,8 +124,6 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi
*/
@Override
public void onFlickGesture(int direction) {
- final int keyEventCode;
-
switch (direction) {
case FlickGestureDetector.FLICK_LEFT:
sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT);
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
index 4cb2f20b9..9141daaee 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -17,7 +17,6 @@
package com.android.inputmethod.accessibility;
import android.content.Context;
-import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Paint;
import android.inputmethodservice.InputMethodService;
@@ -43,8 +42,8 @@ public class AccessibleKeyboardViewProxy {
private Key mLastHoverKey = null;
- public static void init(InputMethodService inputMethod, SharedPreferences prefs) {
- sInstance.initInternal(inputMethod, prefs);
+ public static void init(InputMethodService inputMethod) {
+ sInstance.initInternal(inputMethod);
sInstance.mListener = AccessibleInputMethodServiceProxy.getInstance();
}
@@ -60,7 +59,7 @@ public class AccessibleKeyboardViewProxy {
// Not publicly instantiable.
}
- private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) {
+ private void initInternal(InputMethodService inputMethod) {
final Paint paint = new Paint();
paint.setTextAlign(Paint.Align.LEFT);
paint.setTextSize(14.0f);
@@ -71,8 +70,7 @@ public class AccessibleKeyboardViewProxy {
mGestureDetector = new KeyboardFlickGestureDetector(inputMethod);
}
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event,
- PointerTracker tracker) {
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
if (mView == null) {
Log.e(TAG, "No keyboard view set!");
return false;
@@ -132,9 +130,9 @@ public class AccessibleKeyboardViewProxy {
final Key key = tracker.getKeyOn(x, y);
if (key != mLastHoverKey) {
- fireKeyHoverEvent(tracker, mLastHoverKey, false);
+ fireKeyHoverEvent(mLastHoverKey, false);
mLastHoverKey = key;
- fireKeyHoverEvent(tracker, mLastHoverKey, true);
+ fireKeyHoverEvent(mLastHoverKey, true);
}
return true;
@@ -143,7 +141,7 @@ public class AccessibleKeyboardViewProxy {
return false;
}
- private void fireKeyHoverEvent(PointerTracker tracker, Key key, boolean entering) {
+ private void fireKeyHoverEvent(Key key, boolean entering) {
if (mListener == null) {
Log.e(TAG, "No accessible keyboard action listener set!");
return;
diff --git a/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java b/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java
index 9d99e3131..db12f76ad 100644
--- a/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java
+++ b/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java
@@ -126,7 +126,6 @@ public abstract class FlickGestureDetector {
}
final float distanceSquare = calculateDistanceSquare(mCachedHoverEnter, event);
- final long timeout = event.getEventTime() - mCachedHoverEnter.getEventTime();
switch (event.getAction()) {
case MotionEventCompatUtils.ACTION_HOVER_MOVE:
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
index e01262c20..3d5ab05c3 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
@@ -17,7 +17,6 @@
package com.android.inputmethod.accessibility;
import android.content.Context;
-import android.content.SharedPreferences;
import android.text.TextUtils;
import com.android.inputmethod.keyboard.Key;
@@ -45,8 +44,8 @@ public class KeyCodeDescriptionMapper {
// Map of shift-locked key codes to spoken description resource IDs
private final HashMap<Integer, Integer> mShiftLockedKeyCodeMap;
- public static void init(Context context, SharedPreferences prefs) {
- sInstance.initInternal(context, prefs);
+ public static void init() {
+ sInstance.initInternal();
}
public static KeyCodeDescriptionMapper getInstance() {
@@ -60,7 +59,7 @@ public class KeyCodeDescriptionMapper {
mShiftLockedKeyCodeMap = new HashMap<Integer, Integer>();
}
- private void initInternal(Context context, SharedPreferences prefs) {
+ private void initInternal() {
// Manual label substitutions for key labels with no string resource
mKeyLabelMap.put(":-)", R.string.spoken_description_smiley);
diff --git a/java/src/com/android/inputmethod/compat/ArraysCompatUtils.java b/java/src/com/android/inputmethod/compat/ArraysCompatUtils.java
index f6afbcfe2..011473bef 100644
--- a/java/src/com/android/inputmethod/compat/ArraysCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/ArraysCompatUtils.java
@@ -16,10 +16,14 @@
package com.android.inputmethod.compat;
+import android.util.Log;
+
import java.lang.reflect.Method;
import java.util.Arrays;
public class ArraysCompatUtils {
+ private static final String TAG = ArraysCompatUtils.class.getSimpleName();
+
private static final Method METHOD_Arrays_binarySearch = CompatUtils
.getMethod(Arrays.class, "binarySearch", int[].class, int.class, int.class, int.class);
@@ -33,8 +37,15 @@ public class ArraysCompatUtils {
}
}
- /* package */ static int compatBinarySearch(int[] array, int startIndex, int endIndex,
- int value) {
+ // TODO: Implement fast binary search
+ /* package for testing */
+ static int compatBinarySearch(int[] array, int startIndex, int endIndex, int value) {
+ // Output error log because this method has strict performance penalty.
+ // Note that this method has been called only from spell checker and spell checker exists
+ // only from IceCreamSandwich and after, so that there is no chance on pre-ICS device to
+ // invoke this method.
+ Log.e(TAG, "Invoked expensive binarySearch");
+
if (startIndex > endIndex) throw new IllegalArgumentException();
if (startIndex < 0 || endIndex > array.length) throw new ArrayIndexOutOfBoundsException();
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 4e4ccef18..e1e74fc9a 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -27,16 +27,15 @@ import android.util.Xml;
import com.android.inputmethod.keyboard.internal.KeyStyles;
import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle;
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
-import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.keyboard.internal.MoreKeySpecParser;
-import com.android.inputmethod.keyboard.internal.XmlParseUtils;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.XmlParseUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -73,10 +72,13 @@ public class Key {
private static final int LABEL_FLAGS_WITH_ICON_RIGHT = 0x2000;
private static final int LABEL_FLAGS_AUTO_X_SCALE = 0x4000;
+ // TODO: These icon references could be int (icon attribute id)
/** Icon to display instead of a label. Icon takes precedence over a label */
private Drawable mIcon;
+ /** Icon for disabled state */
+ private Drawable mDisabledIcon;
/** Preview version of the icon, for the preview popup */
- private Drawable mPreviewIcon;
+ public final Drawable mPreviewIcon;
/** Width of the key, not including the gap */
public final int mWidth;
@@ -115,14 +117,14 @@ public class Key {
private static final int ACTION_FLAGS_NO_KEY_PREVIEW = 0x02;
private static final int ACTION_FLAGS_ALT_CODE_WHILE_TYPING = 0x04;
+ private final int mHashCode;
+
/** The current pressed state of this key */
private boolean mPressed;
/** If this is a sticky key, is its highlight on? */
private boolean mHighlightOn;
/** Key is enabled and responds on press */
private boolean mEnabled = true;
- /** Whether this key needs to show the "..." popup hint for special purposes */
- private boolean mNeedsSpecialPopupHint;
// RTL parenthesis character swapping map.
private static final Map<Integer, Integer> sRtlParenthesisMap = new HashMap<Integer, Integer>();
@@ -158,19 +160,19 @@ public class Key {
}
}
- private static int getCode(Resources res, KeyboardParams params, String moreKeySpec) {
+ private static int getCode(Resources res, Keyboard.Params params, String moreKeySpec) {
return getRtlParenthesisCode(
MoreKeySpecParser.getCode(res, moreKeySpec), params.mIsRtlKeyboard);
}
- private static Drawable getIcon(KeyboardParams params, String moreKeySpec) {
- return params.mIconsSet.getIcon(MoreKeySpecParser.getIconId(moreKeySpec));
+ private static Drawable getIcon(Keyboard.Params params, String moreKeySpec) {
+ return params.mIconsSet.getIconByIconId(MoreKeySpecParser.getIconId(moreKeySpec));
}
/**
* This constructor is being used only for key in more keys keyboard.
*/
- public Key(Resources res, KeyboardParams params, String moreKeySpec,
+ public Key(Resources res, Keyboard.Params params, String moreKeySpec,
int x, int y, int width, int height) {
this(params, MoreKeySpecParser.getLabel(moreKeySpec), null, getIcon(params, moreKeySpec),
getCode(res, params, moreKeySpec), MoreKeySpecParser.getOutputText(moreKeySpec),
@@ -180,7 +182,7 @@ public class Key {
/**
* This constructor is being used only for key in popup suggestions pane.
*/
- public Key(KeyboardParams params, CharSequence label, CharSequence hintLabel, Drawable icon,
+ public Key(Keyboard.Params params, CharSequence label, CharSequence hintLabel, Drawable icon,
int code, CharSequence outputText, int x, int y, int width, int height) {
mHeight = height - params.mVerticalGap;
mHorizontalGap = params.mHorizontalGap;
@@ -198,10 +200,14 @@ public class Key {
mCode = code;
mAltCode = Keyboard.CODE_DUMMY;
mIcon = icon;
+ mDisabledIcon = null;
+ mPreviewIcon = null;
// Horizontal gap is divided equally to both sides of the key.
mX = x + mHorizontalGap / 2;
mY = y;
mHitBox.set(x, y, x + width + 1, y + height);
+
+ mHashCode = hashCode(this);
}
/**
@@ -215,7 +221,7 @@ public class Key {
* @param keyStyles active key styles set
* @throws XmlPullParserException
*/
- public Key(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
+ public Key(Resources res, Keyboard.Params params, Keyboard.Builder.Row row,
XmlPullParser parser, KeyStyles keyStyles) throws XmlPullParserException {
final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
final int keyHeight = row.mRowHeight;
@@ -267,20 +273,16 @@ public class Key {
mActionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags, 0);
final KeyboardIconsSet iconsSet = params.mIconsSet;
- mVisualInsetsLeft = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr,
+ mVisualInsetsLeft = (int) Keyboard.Builder.getDimensionOrFraction(keyAttr,
R.styleable.Keyboard_Key_visualInsetsLeft, params.mBaseWidth, 0);
- mVisualInsetsRight = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr,
+ mVisualInsetsRight = (int) Keyboard.Builder.getDimensionOrFraction(keyAttr,
R.styleable.Keyboard_Key_visualInsetsRight, params.mBaseWidth, 0);
- mPreviewIcon = iconsSet.getIcon(style.getInt(keyAttr,
+ mPreviewIcon = iconsSet.getIconByIconId(style.getInt(keyAttr,
R.styleable.Keyboard_Key_keyIconPreview, KeyboardIconsSet.ICON_UNDEFINED));
- mIcon = iconsSet.getIcon(style.getInt(keyAttr, R.styleable.Keyboard_Key_keyIcon,
- KeyboardIconsSet.ICON_UNDEFINED));
- final int shiftedIconId = style.getInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted,
- KeyboardIconsSet.ICON_UNDEFINED);
- if (shiftedIconId != KeyboardIconsSet.ICON_UNDEFINED) {
- final Drawable shiftedIcon = iconsSet.getIcon(shiftedIconId);
- params.addShiftedIcon(this, shiftedIcon);
- }
+ mIcon = iconsSet.getIconByIconId(style.getInt(keyAttr,
+ R.styleable.Keyboard_Key_keyIcon, KeyboardIconsSet.ICON_UNDEFINED));
+ mDisabledIcon = iconsSet.getIconByIconId(style.getInt(keyAttr,
+ R.styleable.Keyboard_Key_keyIconDisabled, KeyboardIconsSet.ICON_UNDEFINED));
mHintLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
mLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyLabel);
@@ -304,23 +306,71 @@ public class Key {
}
mAltCode = style.getInt(keyAttr,
R.styleable.Keyboard_Key_altCode, Keyboard.CODE_DUMMY);
+ mHashCode = hashCode(this);
keyAttr.recycle();
}
- public void markAsLeftEdge(KeyboardParams params) {
+ private static int hashCode(Key key) {
+ return Arrays.hashCode(new Object[] {
+ key.mX,
+ key.mY,
+ key.mWidth,
+ key.mHeight,
+ key.mCode,
+ key.mLabel,
+ key.mHintLabel,
+ // Key can be distinguishable without the following members.
+ // key.mAltCode,
+ // key.mOutputText,
+ // key.mActionFlags,
+ // key.mLabelFlags,
+ // key.mIcon,
+ // key.mPreviewIcon,
+ // key.mBackgroundType,
+ // key.mHorizontalGap,
+ // key.mVerticalGap,
+ // key.mVisualInsetLeft,
+ // key.mVisualInsetRight,
+ // Arrays.hashCode(key.mMoreKeys),
+ // key.mMaxMoreKeysColumn,
+ });
+ }
+
+ private boolean equals(Key o) {
+ if (this == o) return true;
+ return o.mX == mX
+ && o.mY == mY
+ && o.mWidth == mWidth
+ && o.mHeight == mHeight
+ && o.mCode == mCode
+ && TextUtils.equals(o.mLabel, mLabel)
+ && TextUtils.equals(o.mHintLabel, mHintLabel);
+ }
+
+ @Override
+ public int hashCode() {
+ return mHashCode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof Key && equals((Key)o);
+ }
+
+ public void markAsLeftEdge(Keyboard.Params params) {
mHitBox.left = params.mHorizontalEdgesPadding;
}
- public void markAsRightEdge(KeyboardParams params) {
+ public void markAsRightEdge(Keyboard.Params params) {
mHitBox.right = params.mOccupiedWidth - params.mHorizontalEdgesPadding;
}
- public void markAsTopEdge(KeyboardParams params) {
+ public void markAsTopEdge(Keyboard.Params params) {
mHitBox.top = params.mTopPadding;
}
- public void markAsBottomEdge(KeyboardParams params) {
+ public void markAsBottomEdge(Keyboard.Params params) {
mHitBox.bottom = params.mOccupiedHeight + params.mBottomPadding;
}
@@ -393,14 +443,6 @@ public class Key {
return (mLabelFlags & LABEL_FLAGS_HAS_POPUP_HINT) != 0;
}
- public void setNeedsSpecialPopupHint(boolean needsSpecialPopupHint) {
- mNeedsSpecialPopupHint = needsSpecialPopupHint;
- }
-
- public boolean needsSpecialPopupHint() {
- return mNeedsSpecialPopupHint;
- }
-
public boolean hasUppercaseLetter() {
return (mLabelFlags & LABEL_FLAGS_HAS_UPPERCASE_LETTER) != 0;
}
@@ -422,21 +464,14 @@ public class Key {
}
public Drawable getIcon() {
- return mIcon;
- }
-
- public Drawable getPreviewIcon() {
- return mPreviewIcon;
+ return mEnabled ? mIcon : mDisabledIcon;
}
+ // TODO: Get rid of this method.
public void setIcon(Drawable icon) {
mIcon = icon;
}
- public void setPreviewIcon(Drawable icon) {
- mPreviewIcon = icon;
- }
-
/**
* Informs the key that it has been pressed, in case it needs to change its appearance or
* state.
@@ -571,7 +606,7 @@ public class Key {
}
public static class Spacer extends Key {
- public Spacer(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
+ public Spacer(Resources res, Keyboard.Params params, Keyboard.Builder.Row row,
XmlPullParser parser, KeyStyles keyStyles) throws XmlPullParserException {
super(res, params, row, parser, keyStyles);
}
@@ -579,7 +614,7 @@ public class Key {
/**
* This constructor is being used only for divider in more keys keyboard.
*/
- public Spacer(KeyboardParams params, Drawable icon, int x, int y, int width, int height) {
+ public Spacer(Keyboard.Params params, Drawable icon, int x, int y, int width, int height) {
super(params, null, null, icon, Keyboard.CODE_DUMMY, null, x, y, width, height);
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 8e325b65c..0d271625b 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -19,14 +19,12 @@ package com.android.inputmethod.keyboard;
import android.util.Log;
import java.util.Arrays;
-import java.util.List;
public class KeyDetector {
private static final String TAG = KeyDetector.class.getSimpleName();
private static final boolean DEBUG = false;
public static final int NOT_A_CODE = -1;
- private static final int NOT_A_KEY = -1;
private final int mKeyHysteresisDistanceSquared;
@@ -39,7 +37,7 @@ public class KeyDetector {
// working area
private static final int MAX_NEARBY_KEYS = 12;
private final int[] mDistances = new int[MAX_NEARBY_KEYS];
- private final int[] mIndices = new int[MAX_NEARBY_KEYS];
+ private final Key[] mNeighborKeys = new Key[MAX_NEARBY_KEYS];
/**
* This class handles key detection.
@@ -122,7 +120,7 @@ public class KeyDetector {
private void initializeNearbyKeys() {
Arrays.fill(mDistances, Integer.MAX_VALUE);
- Arrays.fill(mIndices, NOT_A_KEY);
+ Arrays.fill(mNeighborKeys, null);
}
/**
@@ -130,14 +128,14 @@ public class KeyDetector {
* If the distance of two keys are the same, the key which the point is on should be considered
* as a closer one.
*
- * @param keyIndex index of the key.
+ * @param key the key to be inserted into the nearby keys buffer.
* @param distance distance between the key's edge and user touched point.
* @param isOnKey true if the point is on the key.
* @return order of the key in the nearby buffer, 0 if it is the nearest key.
*/
- private int sortNearbyKeys(int keyIndex, int distance, boolean isOnKey) {
+ private int sortNearbyKeys(Key key, int distance, boolean isOnKey) {
final int[] distances = mDistances;
- final int[] indices = mIndices;
+ final Key[] neighborKeys = mNeighborKeys;
for (int insertPos = 0; insertPos < distances.length; insertPos++) {
final int comparingDistance = distances[insertPos];
if (distance < comparingDistance || (distance == comparingDistance && isOnKey)) {
@@ -145,11 +143,11 @@ public class KeyDetector {
if (nextPos < distances.length) {
System.arraycopy(distances, insertPos, distances, nextPos,
distances.length - nextPos);
- System.arraycopy(indices, insertPos, indices, nextPos,
- indices.length - nextPos);
+ System.arraycopy(neighborKeys, insertPos, neighborKeys, nextPos,
+ neighborKeys.length - nextPos);
}
distances[insertPos] = distance;
- indices[insertPos] = keyIndex;
+ neighborKeys[insertPos] = key;
return insertPos;
}
}
@@ -157,21 +155,20 @@ public class KeyDetector {
}
private void getNearbyKeyCodes(final int[] allCodes) {
- final List<Key> keys = getKeyboard().mKeys;
- final int[] indices = mIndices;
+ final Key[] neighborKeys = mNeighborKeys;
// allCodes[0] should always have the key code even if it is a non-letter key.
- if (indices[0] == NOT_A_KEY) {
+ if (neighborKeys[0] == null) {
allCodes[0] = NOT_A_CODE;
return;
}
int numCodes = 0;
- for (int j = 0; j < indices.length && numCodes < allCodes.length; j++) {
- final int index = indices[j];
- if (index == NOT_A_KEY)
+ for (int j = 0; j < neighborKeys.length && numCodes < allCodes.length; j++) {
+ final Key key = neighborKeys[j];
+ if (key == null)
break;
- final int code = keys.get(index).mCode;
+ final int code = key.mCode;
// filter out a non-letter key from nearby keys
if (code < Keyboard.CODE_SPACE)
continue;
@@ -191,18 +188,16 @@ public class KeyDetector {
* @return The nearest key
*/
public Key getKeyAndNearbyCodes(int x, int y, final int[] allCodes) {
- final List<Key> keys = getKeyboard().mKeys;
final int touchX = getTouchX(x);
final int touchY = getTouchY(y);
initializeNearbyKeys();
Key primaryKey = null;
- for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) {
- final Key key = keys.get(index);
+ for (final Key key: mKeyboard.getNearestKeys(touchX, touchY)) {
final boolean isOnKey = key.isOnKey(touchX, touchY);
final int distance = key.squaredDistanceToEdge(touchX, touchY);
if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) {
- final int insertedPosition = sortNearbyKeys(index, distance, isOnKey);
+ final int insertedPosition = sortNearbyKeys(key, distance, isOnKey);
if (insertedPosition == 0 && isOnKey) {
primaryKey = key;
}
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 814b52398..d9d28f186 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -16,17 +16,33 @@
package com.android.inputmethod.keyboard;
-import android.graphics.drawable.Drawable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.view.InflateException;
+import com.android.inputmethod.compat.EditorInfoCompatUtils;
+import com.android.inputmethod.keyboard.internal.KeyStyles;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
-import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.keyboard.internal.KeyboardShiftState;
+import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.XmlParseUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -106,11 +122,9 @@ public class Keyboard {
public final boolean mIsRtlKeyboard;
/** List of keys and icons in this keyboard */
- public final List<Key> mKeys;
- public final List<Key> mShiftKeys;
+ public final Set<Key> mKeys;
+ public final Set<Key> mShiftKeys;
public final Set<Key> mShiftLockKeys;
- public final Map<Key, Drawable> mShiftedIcons;
- public final Map<Key, Drawable> mUnshiftedIcons;
public final KeyboardIconsSet mIconsSet;
private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>();
@@ -120,7 +134,7 @@ public class Keyboard {
// TODO: Remove this variable.
private final KeyboardShiftState mShiftState = new KeyboardShiftState();
- public Keyboard(KeyboardParams params) {
+ public Keyboard(Params params) {
mId = params.mId;
mThemeId = params.mThemeId;
mOccupiedHeight = params.mOccupiedHeight;
@@ -134,11 +148,9 @@ public class Keyboard {
mTopPadding = params.mTopPadding;
mVerticalGap = params.mVerticalGap;
- mKeys = Collections.unmodifiableList(params.mKeys);
- mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
+ mKeys = Collections.unmodifiableSet(params.mKeys);
+ mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys);
mShiftLockKeys = Collections.unmodifiableSet(params.mShiftLockKeys);
- mShiftedIcons = Collections.unmodifiableMap(params.mShiftedIcons);
- mUnshiftedIcons = Collections.unmodifiableMap(params.mUnshiftedIcons);
mIconsSet = params.mIconsSet;
mProximityInfo = new ProximityInfo(
@@ -170,17 +182,20 @@ public class Keyboard {
}
// TODO: Remove this method.
- public boolean hasShiftLockKey() {
+ boolean hasShiftLockKey() {
return !mShiftLockKeys.isEmpty();
}
// TODO: Remove this method.
- public void setShiftLocked(boolean newShiftLockState) {
+ void setShiftLocked(boolean newShiftLockState) {
for (final Key key : mShiftLockKeys) {
// To represent "shift locked" state. The highlight is handled by background image that
// might be a StateListDrawable.
key.setHighlightOn(newShiftLockState);
- key.setIcon(newShiftLockState ? mShiftedIcons.get(key) : mUnshiftedIcons.get(key));
+ final int attrId = newShiftLockState
+ ? R.styleable.Keyboard_iconShiftKeyShifted
+ : R.styleable.Keyboard_iconShiftKey;
+ key.setIcon(mIconsSet.getIconByAttrId(attrId));
}
mShiftState.setShiftLocked(newShiftLockState);
}
@@ -191,10 +206,13 @@ public class Keyboard {
}
// TODO: Remove this method.
- public void setShifted(boolean newShiftState) {
+ void setShifted(boolean newShiftState) {
if (!mShiftState.isShiftLocked()) {
for (final Key key : mShiftKeys) {
- key.setIcon(newShiftState ? mShiftedIcons.get(key) : mUnshiftedIcons.get(key));
+ final int attrId = newShiftState
+ ? R.styleable.Keyboard_iconShiftKeyShifted
+ : R.styleable.Keyboard_iconShiftKey;
+ key.setIcon(mIconsSet.getIconByAttrId(attrId));
}
}
mShiftState.setShifted(newShiftState);
@@ -206,7 +224,7 @@ public class Keyboard {
}
// TODO: Remove this method
- public void setAutomaticTemporaryUpperCase() {
+ void setAutomaticTemporaryUpperCase() {
mShiftState.setAutomaticTemporaryUpperCase();
}
@@ -217,22 +235,178 @@ public class Keyboard {
// TODO: Remove this method.
public CharSequence adjustLabelCase(CharSequence label) {
- if (isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) && label.length() < 3
- && Character.isLowerCase(label.charAt(0))) {
+ if (mId.isAlphabetKeyboard() && isShiftedOrShiftLocked() && !TextUtils.isEmpty(label)
+ && label.length() < 3 && Character.isLowerCase(label.charAt(0))) {
return label.toString().toUpperCase(mId.mLocale);
}
return label;
}
+ public static class Params {
+ public KeyboardId mId;
+ public int mThemeId;
+
+ /** Total height and width of the keyboard, including the paddings and keys */
+ public int mOccupiedHeight;
+ public int mOccupiedWidth;
+
+ /** Base height and width of the keyboard used to calculate rows' or keys' heights and
+ * widths
+ */
+ public int mBaseHeight;
+ public int mBaseWidth;
+
+ public int mTopPadding;
+ public int mBottomPadding;
+ public int mHorizontalEdgesPadding;
+ public int mHorizontalCenterPadding;
+
+ public int mDefaultRowHeight;
+ public int mDefaultKeyWidth;
+ public int mHorizontalGap;
+ public int mVerticalGap;
+
+ public boolean mIsRtlKeyboard;
+ public int mMoreKeysTemplate;
+ public int mMaxMiniKeyboardColumn;
+
+ public int GRID_WIDTH;
+ public int GRID_HEIGHT;
+
+ public final Set<Key> mKeys = new HashSet<Key>();
+ public final Set<Key> mShiftKeys = new HashSet<Key>();
+ public final Set<Key> mShiftLockKeys = new HashSet<Key>();
+ public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
+
+ public int mMostCommonKeyHeight = 0;
+ public int mMostCommonKeyWidth = 0;
+
+ public final TouchPositionCorrection mTouchPositionCorrection =
+ new TouchPositionCorrection();
+
+ public static class TouchPositionCorrection {
+ private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3;
+
+ public boolean mEnabled;
+ public float[] mXs;
+ public float[] mYs;
+ public float[] mRadii;
+
+ public void load(String[] data) {
+ final int dataLength = data.length;
+ if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
+ if (LatinImeLogger.sDBG)
+ throw new RuntimeException(
+ "the size of touch position correction data is invalid");
+ return;
+ }
+
+ final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+ mXs = new float[length];
+ mYs = new float[length];
+ mRadii = new float[length];
+ try {
+ for (int i = 0; i < dataLength; ++i) {
+ final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+ final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+ final float value = Float.parseFloat(data[i]);
+ if (type == 0) {
+ mXs[index] = value;
+ } else if (type == 1) {
+ mYs[index] = value;
+ } else {
+ mRadii[index] = value;
+ }
+ }
+ } catch (NumberFormatException e) {
+ if (LatinImeLogger.sDBG) {
+ throw new RuntimeException(
+ "the number format for touch position correction data is invalid");
+ }
+ mXs = null;
+ mYs = null;
+ mRadii = null;
+ }
+ }
+
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ }
+
+ public boolean isValid() {
+ return mEnabled && mXs != null && mYs != null && mRadii != null
+ && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
+ }
+ }
+
+ protected void clearKeys() {
+ mKeys.clear();
+ mShiftKeys.clear();
+ mShiftLockKeys.clear();
+ clearHistogram();
+ }
+
+ public void onAddKey(Key key) {
+ mKeys.add(key);
+ updateHistogram(key);
+ if (key.mCode == Keyboard.CODE_SHIFT) {
+ mShiftKeys.add(key);
+ if (key.isSticky()) {
+ mShiftLockKeys.add(key);
+ }
+ }
+ }
+
+ private int mMaxHeightCount = 0;
+ private int mMaxWidthCount = 0;
+ private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>();
+ private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>();
+
+ private void clearHistogram() {
+ mMostCommonKeyHeight = 0;
+ mMaxHeightCount = 0;
+ mHeightHistogram.clear();
+
+ mMaxWidthCount = 0;
+ mMostCommonKeyWidth = 0;
+ mWidthHistogram.clear();
+ }
+
+ private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) {
+ final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1;
+ histogram.put(key, count);
+ return count;
+ }
+
+ private void updateHistogram(Key key) {
+ final Integer height = key.mHeight + key.mVerticalGap;
+ final int heightCount = updateHistogramCounter(mHeightHistogram, height);
+ if (heightCount > mMaxHeightCount) {
+ mMaxHeightCount = heightCount;
+ mMostCommonKeyHeight = height;
+ }
+
+ final Integer width = key.mWidth + key.mHorizontalGap;
+ final int widthCount = updateHistogramCounter(mWidthHistogram, width);
+ if (widthCount > mMaxWidthCount) {
+ mMaxWidthCount = widthCount;
+ mMostCommonKeyWidth = width;
+ }
+ }
+ }
+
/**
- * Returns the indices of the keys that are closest to the given point.
+ * Returns the array of the keys that are closest to the given point.
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
- * @return the array of integer indices for the nearest keys to the given point. If the given
+ * @return the array of the nearest keys to the given point. If the given
* point is out of range, then an array of size zero is returned.
*/
- public int[] getNearestKeys(int x, int y) {
- return mProximityInfo.getNearestKeys(x, y);
+ public Key[] getNearestKeys(int x, int y) {
+ // Avoid dead pixels at edges of the keyboard
+ final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
+ final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
+ return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
}
public static String printableCode(int code) {
@@ -250,4 +424,812 @@ public class Keyboard {
return String.format("\\u04x", code);
}
}
+
+ /**
+ * Keyboard Building helper.
+ *
+ * This class parses Keyboard XML file and eventually build a Keyboard.
+ * The Keyboard XML file looks like:
+ * <pre>
+ * &gt;!-- xml/keyboard.xml --&lt;
+ * &gt;Keyboard keyboard_attributes*&lt;
+ * &gt;!-- Keyboard Content --&lt;
+ * &gt;Row row_attributes*&lt;
+ * &gt;!-- Row Content --&lt;
+ * &gt;Key key_attributes* /&lt;
+ * &gt;Spacer horizontalGap="0.2in" /&lt;
+ * &gt;include keyboardLayout="@xml/other_keys"&lt;
+ * ...
+ * &gt;/Row&lt;
+ * &gt;include keyboardLayout="@xml/other_rows"&lt;
+ * ...
+ * &gt;/Keyboard&lt;
+ * </pre>
+ * The XML file which is included in other file must have &gt;merge&lt; as root element,
+ * such as:
+ * <pre>
+ * &gt;!-- xml/other_keys.xml --&lt;
+ * &gt;merge&lt;
+ * &gt;Key key_attributes* /&lt;
+ * ...
+ * &gt;/merge&lt;
+ * </pre>
+ * and
+ * <pre>
+ * &gt;!-- xml/other_rows.xml --&lt;
+ * &gt;merge&lt;
+ * &gt;Row row_attributes*&lt;
+ * &gt;Key key_attributes* /&lt;
+ * &gt;/Row&lt;
+ * ...
+ * &gt;/merge&lt;
+ * </pre>
+ * You can also use switch-case-default tags to select Rows and Keys.
+ * <pre>
+ * &gt;switch&lt;
+ * &gt;case case_attribute*&lt;
+ * &gt;!-- Any valid tags at switch position --&lt;
+ * &gt;/case&lt;
+ * ...
+ * &gt;default&lt;
+ * &gt;!-- Any valid tags at switch position --&lt;
+ * &gt;/default&lt;
+ * &gt;/switch&lt;
+ * </pre>
+ * You can declare Key style and specify styles within Key tags.
+ * <pre>
+ * &gt;switch&lt;
+ * &gt;case mode="email"&lt;
+ * &gt;key-style styleName="f1-key" parentStyle="modifier-key"
+ * keyLabel=".com"
+ * /&lt;
+ * &gt;/case&lt;
+ * &gt;case mode="url"&lt;
+ * &gt;key-style styleName="f1-key" parentStyle="modifier-key"
+ * keyLabel="http://"
+ * /&lt;
+ * &gt;/case&lt;
+ * &gt;/switch&lt;
+ * ...
+ * &gt;Key keyStyle="shift-key" ... /&lt;
+ * </pre>
+ */
+
+ public static class Builder<KP extends Params> {
+ private static final String TAG = Builder.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ // Keyboard XML Tags
+ private static final String TAG_KEYBOARD = "Keyboard";
+ private static final String TAG_ROW = "Row";
+ private static final String TAG_KEY = "Key";
+ private static final String TAG_SPACER = "Spacer";
+ private static final String TAG_INCLUDE = "include";
+ private static final String TAG_MERGE = "merge";
+ private static final String TAG_SWITCH = "switch";
+ private static final String TAG_CASE = "case";
+ private static final String TAG_DEFAULT = "default";
+ public static final String TAG_KEY_STYLE = "key-style";
+
+ private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
+ private static final int DEFAULT_KEYBOARD_ROWS = 4;
+
+ protected final KP mParams;
+ protected final Context mContext;
+ protected final Resources mResources;
+ private final DisplayMetrics mDisplayMetrics;
+
+ private int mCurrentY = 0;
+ private Row mCurrentRow = null;
+ private boolean mLeftEdge;
+ private boolean mTopEdge;
+ private Key mRightEdgeKey = null;
+ private final KeyStyles mKeyStyles = new KeyStyles();
+
+ /**
+ * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
+ * Some of the key size defaults can be overridden per row from what the {@link Keyboard}
+ * defines.
+ */
+ public static class Row {
+ // keyWidth enum constants
+ private static final int KEYWIDTH_NOT_ENUM = 0;
+ private static final int KEYWIDTH_FILL_RIGHT = -1;
+ private static final int KEYWIDTH_FILL_BOTH = -2;
+
+ private final Params mParams;
+ /** Default width of a key in this row. */
+ public final float mDefaultKeyWidth;
+ /** Default height of a key in this row. */
+ public final int mRowHeight;
+
+ private final int mCurrentY;
+ // Will be updated by {@link Key}'s constructor.
+ private float mCurrentX;
+
+ public Row(Resources res, Params params, XmlPullParser parser, int y) {
+ mParams = params;
+ TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard);
+ mRowHeight = (int)Builder.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_rowHeight,
+ params.mBaseHeight, params.mDefaultRowHeight);
+ keyboardAttr.recycle();
+ TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Key);
+ mDefaultKeyWidth = Builder.getDimensionOrFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth,
+ params.mBaseWidth, params.mDefaultKeyWidth);
+ keyAttr.recycle();
+
+ mCurrentY = y;
+ mCurrentX = 0.0f;
+ }
+
+ public void setXPos(float keyXPos) {
+ mCurrentX = keyXPos;
+ }
+
+ public void advanceXPos(float width) {
+ mCurrentX += width;
+ }
+
+ public int getKeyY() {
+ return mCurrentY;
+ }
+
+ public float getKeyX(TypedArray keyAttr) {
+ final int widthType = Builder.getEnumValue(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
+ if (widthType == KEYWIDTH_FILL_BOTH) {
+ // If keyWidth is fillBoth, the key width should start right after the nearest
+ // key on the left hand side.
+ return mCurrentX;
+ }
+
+ final int keyboardRightEdge = mParams.mOccupiedWidth
+ - mParams.mHorizontalEdgesPadding;
+ if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
+ final float keyXPos = Builder.getDimensionOrFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0);
+ if (keyXPos < 0) {
+ // If keyXPos is negative, the actual x-coordinate will be
+ // keyboardWidth + keyXPos.
+ // keyXPos shouldn't be less than mCurrentX because drawable area for this
+ // key starts at mCurrentX. Or, this key will overlaps the adjacent key on
+ // its left hand side.
+ return Math.max(keyXPos + keyboardRightEdge, mCurrentX);
+ } else {
+ return keyXPos + mParams.mHorizontalEdgesPadding;
+ }
+ }
+ return mCurrentX;
+ }
+
+ public float getKeyWidth(TypedArray keyAttr, float keyXPos) {
+ final int widthType = Builder.getEnumValue(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
+ switch (widthType) {
+ case KEYWIDTH_FILL_RIGHT:
+ case KEYWIDTH_FILL_BOTH:
+ final int keyboardRightEdge =
+ mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding;
+ // If keyWidth is fillRight, the actual key width will be determined to fill
+ // out the area up to the right edge of the keyboard.
+ // If keyWidth is fillBoth, the actual key width will be determined to fill out
+ // the area between the nearest key on the left hand side and the right edge of
+ // the keyboard.
+ return keyboardRightEdge - keyXPos;
+ default: // KEYWIDTH_NOT_ENUM
+ return Builder.getDimensionOrFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth,
+ mParams.mBaseWidth, mDefaultKeyWidth);
+ }
+ }
+ }
+
+ public Builder(Context context, KP params) {
+ mContext = context;
+ final Resources res = context.getResources();
+ mResources = res;
+ mDisplayMetrics = res.getDisplayMetrics();
+
+ mParams = params;
+
+ setTouchPositionCorrectionData(context, params);
+
+ params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
+ params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
+ }
+
+ private static void setTouchPositionCorrectionData(Context context, Params params) {
+ final TypedArray a = context.obtainStyledAttributes(
+ null, R.styleable.Keyboard, R.attr.keyboardStyle, 0);
+ params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0);
+ final int resourceId = a.getResourceId(
+ R.styleable.Keyboard_touchPositionCorrectionData, 0);
+ a.recycle();
+ if (resourceId == 0) {
+ if (LatinImeLogger.sDBG)
+ throw new RuntimeException("touchPositionCorrectionData is not defined");
+ return;
+ }
+
+ final String[] data = context.getResources().getStringArray(resourceId);
+ params.mTouchPositionCorrection.load(data);
+ }
+
+ public Builder<KP> load(int xmlId, KeyboardId id) {
+ mParams.mId = id;
+ final XmlResourceParser parser = mResources.getXml(xmlId);
+ try {
+ parseKeyboard(parser);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "keyboard XML parse error: " + e);
+ throw new IllegalArgumentException(e);
+ } catch (IOException e) {
+ Log.w(TAG, "keyboard XML parse error: " + e);
+ throw new RuntimeException(e);
+ } finally {
+ parser.close();
+ }
+ return this;
+ }
+
+ public void setTouchPositionCorrectionEnabled(boolean enabled) {
+ mParams.mTouchPositionCorrection.setEnabled(enabled);
+ }
+
+ public Keyboard build() {
+ return new Keyboard(mParams);
+ }
+
+ private void parseKeyboard(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mParams.mId));
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_KEYBOARD.equals(tag)) {
+ parseKeyboardAttributes(parser);
+ startKeyboard();
+ parseKeyboardContent(parser, false);
+ break;
+ } else {
+ throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD);
+ }
+ }
+ }
+ }
+
+ private void parseKeyboardAttributes(XmlPullParser parser) {
+ final int displayWidth = mDisplayMetrics.widthPixels;
+ final TypedArray keyboardAttr = mContext.obtainStyledAttributes(
+ Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle,
+ R.style.Keyboard);
+ final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Key);
+ try {
+ final int displayHeight = mDisplayMetrics.heightPixels;
+ final int keyboardHeight = (int)keyboardAttr.getDimension(
+ R.styleable.Keyboard_keyboardHeight, displayHeight / 2);
+ final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2);
+ int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2);
+ if (minKeyboardHeight < 0) {
+ // Specified fraction was negative, so it should be calculated against display
+ // width.
+ minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2);
+ }
+ final Params params = mParams;
+ // Keyboard height will not exceed maxKeyboardHeight and will not be less than
+ // minKeyboardHeight.
+ params.mOccupiedHeight = Math.max(
+ Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
+ params.mOccupiedWidth = params.mId.mWidth;
+ params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0);
+ params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0);
+ params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_keyboardHorizontalEdgesPadding,
+ mParams.mOccupiedWidth, 0);
+
+ params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2
+ - params.mHorizontalCenterPadding;
+ params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth,
+ params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS);
+ params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0);
+ params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0);
+ params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding
+ - params.mBottomPadding + params.mVerticalGap;
+ params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_rowHeight, params.mBaseHeight,
+ params.mBaseHeight / DEFAULT_KEYBOARD_ROWS);
+
+ params.mIsRtlKeyboard = keyboardAttr.getBoolean(
+ R.styleable.Keyboard_isRtlKeyboard, false);
+ params.mMoreKeysTemplate = keyboardAttr.getResourceId(
+ R.styleable.Keyboard_moreKeysTemplate, 0);
+ params.mMaxMiniKeyboardColumn = keyAttr.getInt(
+ R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);
+
+ params.mIconsSet.loadIcons(keyboardAttr);
+ } finally {
+ keyAttr.recycle();
+ keyboardAttr.recycle();
+ }
+ }
+
+ private void parseKeyboardContent(XmlPullParser parser, boolean skip)
+ throws XmlPullParserException, IOException {
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_ROW.equals(tag)) {
+ Row row = parseRowAttributes(parser);
+ if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW));
+ if (!skip)
+ startRow(row);
+ parseRowContent(parser, row, skip);
+ } else if (TAG_INCLUDE.equals(tag)) {
+ parseIncludeKeyboardContent(parser, skip);
+ } else if (TAG_SWITCH.equals(tag)) {
+ parseSwitchKeyboardContent(parser, skip);
+ } else if (TAG_KEY_STYLE.equals(tag)) {
+ parseKeyStyle(parser, skip);
+ } else {
+ throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW);
+ }
+ } else if (event == XmlPullParser.END_TAG) {
+ final String tag = parser.getName();
+ if (TAG_KEYBOARD.equals(tag)) {
+ endKeyboard();
+ break;
+ } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)
+ || TAG_MERGE.equals(tag)) {
+ if (DEBUG) Log.d(TAG, String.format("</%s>", tag));
+ break;
+ } else if (TAG_KEY_STYLE.equals(tag)) {
+ continue;
+ } else {
+ throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW);
+ }
+ }
+ }
+ }
+
+ private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException {
+ final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard);
+ try {
+ if (a.hasValue(R.styleable.Keyboard_horizontalGap))
+ throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap");
+ if (a.hasValue(R.styleable.Keyboard_verticalGap))
+ throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap");
+ return new Row(mResources, mParams, parser, mCurrentY);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ private void parseRowContent(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_KEY.equals(tag)) {
+ parseKey(parser, row, skip);
+ } else if (TAG_SPACER.equals(tag)) {
+ parseSpacer(parser, row, skip);
+ } else if (TAG_INCLUDE.equals(tag)) {
+ parseIncludeRowContent(parser, row, skip);
+ } else if (TAG_SWITCH.equals(tag)) {
+ parseSwitchRowContent(parser, row, skip);
+ } else if (TAG_KEY_STYLE.equals(tag)) {
+ parseKeyStyle(parser, skip);
+ } else {
+ throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
+ }
+ } else if (event == XmlPullParser.END_TAG) {
+ final String tag = parser.getName();
+ if (TAG_ROW.equals(tag)) {
+ if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_ROW));
+ if (!skip)
+ endRow(row);
+ break;
+ } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)
+ || TAG_MERGE.equals(tag)) {
+ if (DEBUG) Log.d(TAG, String.format("</%s>", tag));
+ break;
+ } else if (TAG_KEY_STYLE.equals(tag)) {
+ continue;
+ } else {
+ throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
+ }
+ }
+ }
+ }
+
+ private void parseKey(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ if (skip) {
+ XmlParseUtils.checkEndTag(TAG_KEY, parser);
+ } else {
+ final Key key = new Key(mResources, mParams, row, parser, mKeyStyles);
+ if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />",
+ TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode,
+ Arrays.toString(key.mMoreKeys)));
+ XmlParseUtils.checkEndTag(TAG_KEY, parser);
+ endKey(key);
+ }
+ }
+
+ private void parseSpacer(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ if (skip) {
+ XmlParseUtils.checkEndTag(TAG_SPACER, parser);
+ } else {
+ final Key.Spacer spacer = new Key.Spacer(
+ mResources, mParams, row, parser, mKeyStyles);
+ if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER));
+ XmlParseUtils.checkEndTag(TAG_SPACER, parser);
+ endKey(spacer);
+ }
+ }
+
+ private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip)
+ throws XmlPullParserException, IOException {
+ parseIncludeInternal(parser, null, skip);
+ }
+
+ private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ parseIncludeInternal(parser, row, skip);
+ }
+
+ private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ if (skip) {
+ XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
+ } else {
+ final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Include);
+ int keyboardLayout = 0;
+ try {
+ XmlParseUtils.checkAttributeExists(a,
+ R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout",
+ TAG_INCLUDE, parser);
+ keyboardLayout = a.getResourceId(
+ R.styleable.Keyboard_Include_keyboardLayout, 0);
+ } finally {
+ a.recycle();
+ }
+
+ XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
+ if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />",
+ TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout)));
+ final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout);
+ try {
+ parseMerge(parserForInclude, row, skip);
+ } finally {
+ parserForInclude.close();
+ }
+ }
+ }
+
+ private void parseMerge(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_MERGE.equals(tag)) {
+ if (row == null) {
+ parseKeyboardContent(parser, skip);
+ } else {
+ parseRowContent(parser, row, skip);
+ }
+ break;
+ } else {
+ throw new XmlParseUtils.ParseException(
+ "Included keyboard layout must have <merge> root element", parser);
+ }
+ }
+ }
+ }
+
+ private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip)
+ throws XmlPullParserException, IOException {
+ parseSwitchInternal(parser, null, skip);
+ }
+
+ private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ parseSwitchInternal(parser, row, skip);
+ }
+
+ private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mParams.mId));
+ boolean selected = false;
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_CASE.equals(tag)) {
+ selected |= parseCase(parser, row, selected ? true : skip);
+ } else if (TAG_DEFAULT.equals(tag)) {
+ selected |= parseDefault(parser, row, selected ? true : skip);
+ } else {
+ throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
+ }
+ } else if (event == XmlPullParser.END_TAG) {
+ final String tag = parser.getName();
+ if (TAG_SWITCH.equals(tag)) {
+ if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_SWITCH));
+ break;
+ } else {
+ throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
+ }
+ }
+ }
+ }
+
+ private boolean parseCase(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ final boolean selected = parseCaseCondition(parser);
+ if (row == null) {
+ // Processing Rows.
+ parseKeyboardContent(parser, selected ? skip : true);
+ } else {
+ // Processing Keys.
+ parseRowContent(parser, row, selected ? skip : true);
+ }
+ return selected;
+ }
+
+ private boolean parseCaseCondition(XmlPullParser parser) {
+ final KeyboardId id = mParams.mId;
+ if (id == null)
+ return true;
+
+ final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Case);
+ try {
+ final boolean modeMatched = matchTypedValue(a,
+ R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode));
+ final boolean navigateActionMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_navigateAction, id.navigateAction());
+ final boolean passwordInputMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_passwordInput, id.passwordInput());
+ final boolean hasSettingsKeyMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_hasSettingsKey, id.hasSettingsKey());
+ final boolean f2KeyModeMatched = matchInteger(a,
+ R.styleable.Keyboard_Case_f2KeyMode, id.f2KeyMode());
+ final boolean clobberSettingsKeyMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey);
+ final boolean shortcutKeyEnabledMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled);
+ final boolean hasShortcutKeyMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey);
+ // As noted at {@link KeyboardId} class, we are interested only in enum value
+ // masked by {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and
+ // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching
+ // this attribute with id.mImeOptions as integer value is enough for our purpose.
+ final boolean imeActionMatched = matchInteger(a,
+ R.styleable.Keyboard_Case_imeAction, id.imeAction());
+ final boolean localeCodeMatched = matchString(a,
+ R.styleable.Keyboard_Case_localeCode, id.mLocale.toString());
+ final boolean languageCodeMatched = matchString(a,
+ R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
+ final boolean countryCodeMatched = matchString(a,
+ R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
+ final boolean selected = modeMatched && navigateActionMatched
+ && passwordInputMatched && hasSettingsKeyMatched && f2KeyModeMatched
+ && clobberSettingsKeyMatched && shortcutKeyEnabledMatched
+ && hasShortcutKeyMatched && imeActionMatched && localeCodeMatched
+ && languageCodeMatched && countryCodeMatched;
+
+ if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
+ textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"),
+ booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"),
+ booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
+ booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"),
+ textAttr(KeyboardId.f2KeyModeName(
+ a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), "f2KeyMode"),
+ booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey,
+ "clobberSettingsKey"),
+ booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled,
+ "shortcutKeyEnabled"),
+ booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"),
+ textAttr(EditorInfoCompatUtils.imeOptionsName(
+ a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"),
+ textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), "localeCode"),
+ textAttr(a.getString(R.styleable.Keyboard_Case_languageCode),
+ "languageCode"),
+ textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"),
+ Boolean.toString(selected)));
+
+ return selected;
+ } finally {
+ a.recycle();
+ }
+ }
+
+ private static boolean matchInteger(TypedArray a, int index, int value) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for
+ // the attribute.
+ return !a.hasValue(index) || a.getInt(index, 0) == value;
+ }
+
+ private static boolean matchBoolean(TypedArray a, int index, boolean value) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for
+ // the attribute.
+ return !a.hasValue(index) || a.getBoolean(index, false) == value;
+ }
+
+ private static boolean matchString(TypedArray a, int index, String value) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for
+ // the attribute.
+ return !a.hasValue(index)
+ || stringArrayContains(a.getString(index).split("\\|"), value);
+ }
+
+ private static boolean matchTypedValue(TypedArray a, int index, int intValue,
+ String strValue) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for
+ // the attribute.
+ final TypedValue v = a.peekValue(index);
+ if (v == null)
+ return true;
+
+ if (isIntegerValue(v)) {
+ return intValue == a.getInt(index, 0);
+ } else if (isStringValue(v)) {
+ return stringArrayContains(a.getString(index).split("\\|"), strValue);
+ }
+ return false;
+ }
+
+ private static boolean stringArrayContains(String[] array, String value) {
+ for (final String elem : array) {
+ if (elem.equals(value))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean parseDefault(XmlPullParser parser, Row row, boolean skip)
+ throws XmlPullParserException, IOException {
+ if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT));
+ if (row == null) {
+ parseKeyboardContent(parser, skip);
+ } else {
+ parseRowContent(parser, row, skip);
+ }
+ return true;
+ }
+
+ private void parseKeyStyle(XmlPullParser parser, boolean skip)
+ throws XmlPullParserException {
+ TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_KeyStyle);
+ TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Key);
+ try {
+ if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName))
+ throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE
+ + "/> needs styleName attribute", parser);
+ if (!skip)
+ mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
+ } finally {
+ keyStyleAttr.recycle();
+ keyAttrs.recycle();
+ }
+ }
+
+ private void startKeyboard() {
+ mCurrentY += mParams.mTopPadding;
+ mTopEdge = true;
+ }
+
+ private void startRow(Row row) {
+ addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
+ mCurrentRow = row;
+ mLeftEdge = true;
+ mRightEdgeKey = null;
+ }
+
+ private void endRow(Row row) {
+ if (mCurrentRow == null)
+ throw new InflateException("orphant end row tag");
+ if (mRightEdgeKey != null) {
+ mRightEdgeKey.markAsRightEdge(mParams);
+ mRightEdgeKey = null;
+ }
+ addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
+ mCurrentY += row.mRowHeight;
+ mCurrentRow = null;
+ mTopEdge = false;
+ }
+
+ private void endKey(Key key) {
+ mParams.onAddKey(key);
+ if (mLeftEdge) {
+ key.markAsLeftEdge(mParams);
+ mLeftEdge = false;
+ }
+ if (mTopEdge) {
+ key.markAsTopEdge(mParams);
+ }
+ mRightEdgeKey = key;
+ }
+
+ private void endKeyboard() {
+ // nothing to do here.
+ }
+
+ private void addEdgeSpace(float width, Row row) {
+ row.advanceXPos(width);
+ mLeftEdge = false;
+ mRightEdgeKey = null;
+ }
+
+ public static float getDimensionOrFraction(TypedArray a, int index, int base,
+ float defValue) {
+ final TypedValue value = a.peekValue(index);
+ if (value == null)
+ return defValue;
+ if (isFractionValue(value)) {
+ return a.getFraction(index, base, base, defValue);
+ } else if (isDimensionValue(value)) {
+ return a.getDimension(index, defValue);
+ }
+ return defValue;
+ }
+
+ public static int getEnumValue(TypedArray a, int index, int defValue) {
+ final TypedValue value = a.peekValue(index);
+ if (value == null)
+ return defValue;
+ if (isIntegerValue(value)) {
+ return a.getInt(index, defValue);
+ }
+ return defValue;
+ }
+
+ private static boolean isFractionValue(TypedValue v) {
+ return v.type == TypedValue.TYPE_FRACTION;
+ }
+
+ private static boolean isDimensionValue(TypedValue v) {
+ return v.type == TypedValue.TYPE_DIMENSION;
+ }
+
+ private static boolean isIntegerValue(TypedValue v) {
+ return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT;
+ }
+
+ private static boolean isStringValue(TypedValue v) {
+ return v.type == TypedValue.TYPE_STRING;
+ }
+
+ private static String textAttr(String value, String name) {
+ return value != null ? String.format(" %s=%s", name, value) : "";
+ }
+
+ private static String booleanAttr(TypedArray a, int index, String name) {
+ return a.hasValue(index)
+ ? String.format(" %s=%s", name, a.getBoolean(index, false)) : "";
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 3b3ff0709..d95c3b3af 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -60,8 +60,6 @@ public class KeyboardId {
public final int mOrientation;
public final int mWidth;
public final int mMode;
- // TODO: Remove this field.
- private final int mXmlId;
public final int mElementState;
private final int mInputType;
private final int mImeOptions;
@@ -72,23 +70,13 @@ public class KeyboardId {
private final int mHashCode;
- public KeyboardId(int xmlId, int elementState, Locale locale, int orientation, int width,
- int mode, EditorInfo editorInfo, boolean settingsKeyEnabled,
- boolean clobberSettingsKey, boolean shortcutKeyEnabled, boolean hasShortcutKey) {
- this(xmlId, elementState, locale, orientation, width, mode,
- (editorInfo != null ? editorInfo.inputType : 0),
- (editorInfo != null ? editorInfo.imeOptions : 0),
- settingsKeyEnabled, clobberSettingsKey, shortcutKeyEnabled, hasShortcutKey);
- }
-
- private KeyboardId(int xmlId, int elementState, Locale locale, int orientation, int width,
- int mode, int inputType, int imeOptions, boolean settingsKeyEnabled,
- boolean clobberSettingsKey, boolean shortcutKeyEnabled, boolean hasShortcutKey) {
+ public KeyboardId(int elementState, Locale locale, int orientation, int width, int mode,
+ int inputType, int imeOptions, boolean settingsKeyEnabled, boolean clobberSettingsKey,
+ boolean shortcutKeyEnabled, boolean hasShortcutKey) {
this.mLocale = locale;
this.mOrientation = orientation;
this.mWidth = width;
this.mMode = mode;
- this.mXmlId = xmlId;
this.mElementState = elementState;
this.mInputType = inputType;
this.mImeOptions = imeOptions;
@@ -106,7 +94,6 @@ public class KeyboardId {
id.mElementState,
id.mMode,
id.mWidth,
- id.mXmlId,
id.navigateAction(),
id.passwordInput(),
id.mSettingsKeyEnabled,
@@ -125,7 +112,6 @@ public class KeyboardId {
&& other.mElementState == this.mElementState
&& other.mMode == this.mMode
&& other.mWidth == this.mWidth
- && other.mXmlId == this.mXmlId
&& other.navigateAction() == this.navigateAction()
&& other.passwordInput() == this.passwordInput()
&& other.mSettingsKeyEnabled == this.mSettingsKeyEnabled
@@ -136,16 +122,6 @@ public class KeyboardId {
&& other.mLocale.equals(this.mLocale);
}
- public KeyboardId cloneWithNewXml(int xmlId) {
- return new KeyboardId(xmlId, mElementState, mLocale, mOrientation, mWidth, mMode,
- mInputType, mImeOptions, false, false, false, false);
- }
-
- // Remove this method.
- public int getXmlId() {
- return mXmlId;
- }
-
public boolean isAlphabetKeyboard() {
return mElementState < ELEMENT_SYMBOLS;
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index a28cfa85d..a2e784c99 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -17,94 +17,178 @@
package com.android.inputmethod.keyboard;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.Xml;
import android.view.inputmethod.EditorInfo;
-import com.android.inputmethod.keyboard.internal.XmlParseUtils;
import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.LocaleUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SettingsValues;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.Utils;
+import com.android.inputmethod.latin.XmlParseUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Locale;
/**
- * This class has a set of {@link KeyboardId}s. Each of them represents a different keyboard
+ * This class represents a set of keyboards. Each of them represents a different keyboard
* specific to a keyboard state, such as alphabet, symbols, and so on. Layouts in the same
* {@link KeyboardSet} are related to each other.
* A {@link KeyboardSet} needs to be created for each {@link android.view.inputmethod.EditorInfo}.
*/
public class KeyboardSet {
- private static final String TAG_KEYBOARD_SET = "KeyboardSet";
+ private static final String TAG = KeyboardSet.class.getSimpleName();
+ private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG;
+
+ private static final String TAG_KEYBOARD_SET = TAG;
private static final String TAG_ELEMENT = "Element";
- // TODO: Make these KeyboardId private.
- public final KeyboardId mAlphabetId;
- public final KeyboardId mSymbolsId;
- public final KeyboardId mSymbolsShiftedId;
+ private final Context mContext;
+ private final Params mParams;
+
+ private static class Params {
+ int mMode;
+ int mInputType;
+ int mImeOptions;
+ boolean mSettingsKeyEnabled;
+ boolean mVoiceKeyEnabled;
+ boolean mVoiceKeyOnMain;
+ boolean mNoSettingsKey;
+ Locale mLocale;
+ int mOrientation;
+ int mWidth;
+ final HashMap<Integer, Integer> mElementKeyboards = new HashMap<Integer, Integer>();
+ Params() {}
+ }
+
+ private static final HashMap<KeyboardId, SoftReference<Keyboard>> sKeyboardCache =
+ new HashMap<KeyboardId, SoftReference<Keyboard>>();
+
+ public static void clearKeyboardCache() {
+ sKeyboardCache.clear();
+ }
+
+ private KeyboardSet(Context context, Params params) {
+ mContext = context;
+ mParams = params;
+ }
+
+ public Keyboard getMainKeyboard() {
+ return getKeyboard(false, false);
+ }
+
+ public Keyboard getSymbolsKeyboard() {
+ return getKeyboard(true, false);
+ }
+
+ public Keyboard getSymbolsShiftedKeyboard() {
+ final Keyboard keyboard = getKeyboard(true, true);
+ // TODO: Remove this logic once we introduce initial keyboard shift state attribute.
+ // Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a.
+ // sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked()
+ // that takes care of the current keyboard having such shift key or not.
+ keyboard.setShiftLocked(keyboard.hasShiftLockKey());
+ return keyboard;
+ }
- KeyboardSet(Builder builder) {
- mAlphabetId = builder.getKeyboardId(false, false);
- mSymbolsId = builder.getKeyboardId(true, false);
- mSymbolsShiftedId = builder.getKeyboardId(true, true);
+ private Keyboard getKeyboard(boolean isSymbols, boolean isShift) {
+ final int elementState = Builder.getElementState(mParams.mMode, isSymbols, isShift);
+ final int xmlId = mParams.mElementKeyboards.get(elementState);
+ final KeyboardId id = Builder.getKeyboardId(elementState, isSymbols, mParams);
+ final Keyboard keyboard = getKeyboard(mContext, xmlId, id);
+ return keyboard;
+ }
+
+ public KeyboardId getMainKeyboardId() {
+ final int elementState = Builder.getElementState(mParams.mMode, false, false);
+ return Builder.getKeyboardId(elementState, false, mParams);
+ }
+
+ private static Keyboard getKeyboard(Context context, int xmlId, KeyboardId id) {
+ final Resources res = context.getResources();
+ final SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
+ final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
+ Keyboard keyboard = (ref == null) ? null : ref.get();
+ if (keyboard == null) {
+ final Locale savedLocale = LocaleUtils.setSystemLocale(res, id.mLocale);
+ try {
+ final Keyboard.Builder<Keyboard.Params> builder =
+ new Keyboard.Builder<Keyboard.Params>(context, new Keyboard.Params());
+ builder.load(xmlId, id);
+ builder.setTouchPositionCorrectionEnabled(
+ subtypeSwitcher.currentSubtypeContainsExtraValueKey(
+ LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION));
+ keyboard = builder.build();
+ } finally {
+ LocaleUtils.setSystemLocale(res, savedLocale);
+ }
+ sKeyboardCache.put(id, new SoftReference<Keyboard>(keyboard));
+
+ if (DEBUG_CACHE) {
+ Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": "
+ + ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
+ }
+ } else if (DEBUG_CACHE) {
+ Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": HIT id=" + id);
+ }
+
+ // TODO: Remove setShiftLocked and setShift calls.
+ keyboard.setShiftLocked(false);
+ keyboard.setShifted(false);
+ return keyboard;
}
public static class Builder {
+ private final Context mContext;
private final Resources mResources;
- private final EditorInfo mEditorInfo;
-
- private final HashMap<Integer, Integer> mElementKeyboards =
- new HashMap<Integer, Integer>();
- private final int mMode;
- private final boolean mSettingsKeyEnabled;
- private final boolean mVoiceKeyEnabled;
- private final boolean mVoiceKeyOnMain;
- private final boolean mNoSettingsKey;
- private final Locale mLocale;
- private final Configuration mConf;
- private final DisplayMetrics mMetrics;
+ private final Params mParams = new Params();
public Builder(Context context, EditorInfo editorInfo, SettingsValues settingsValues) {
+ mContext = context;
mResources = context.getResources();
- mEditorInfo = editorInfo;
final SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
final String packageName = context.getPackageName();
+ final Params params = mParams;
- mMode = Utils.getKeyboardMode(mEditorInfo);
- mSettingsKeyEnabled = settingsValues.isSettingsKeyEnabled();
+ params.mMode = Utils.getKeyboardMode(editorInfo);
+ if (editorInfo != null) {
+ params.mInputType = editorInfo.inputType;
+ params.mImeOptions = editorInfo.imeOptions;
+ }
+ params.mSettingsKeyEnabled = settingsValues.isSettingsKeyEnabled();
@SuppressWarnings("deprecation")
final boolean noMicrophone = Utils.inPrivateImeOptions(
packageName, LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo)
|| Utils.inPrivateImeOptions(
null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo);
- mVoiceKeyEnabled = settingsValues.isVoiceKeyEnabled(editorInfo) && !noMicrophone;
- mVoiceKeyOnMain = settingsValues.isVoiceKeyOnMain();
- mNoSettingsKey = Utils.inPrivateImeOptions(
+ params.mVoiceKeyEnabled = settingsValues.isVoiceKeyEnabled(editorInfo) && !noMicrophone;
+ params.mVoiceKeyOnMain = settingsValues.isVoiceKeyOnMain();
+ params.mNoSettingsKey = Utils.inPrivateImeOptions(
packageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, editorInfo);
final boolean forceAscii = Utils.inPrivateImeOptions(
packageName, LatinIME.IME_OPTION_FORCE_ASCII, editorInfo);
final boolean asciiCapable = subtypeSwitcher.currentSubtypeContainsExtraValueKey(
LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE);
- mLocale = (forceAscii && !asciiCapable) ? Locale.US : subtypeSwitcher.getInputLocale();
- mConf = mResources.getConfiguration();
- mMetrics = mResources.getDisplayMetrics();
+ params.mLocale = (forceAscii && !asciiCapable)
+ ? Locale.US : subtypeSwitcher.getInputLocale();
+ params.mOrientation = mResources.getConfiguration().orientation;
+ params.mWidth = mResources.getDisplayMetrics().widthPixels;
}
public KeyboardSet build() {
- final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, mLocale);
+ final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, mParams.mLocale);
try {
parseKeyboardSet(mResources, R.xml.keyboard_set);
} catch (Exception e) {
@@ -112,19 +196,20 @@ public class KeyboardSet {
} finally {
LocaleUtils.setSystemLocale(mResources, savedLocale);
}
- return new KeyboardSet(this);
+ return new KeyboardSet(mContext, mParams);
}
- KeyboardId getKeyboardId(boolean isSymbols, boolean isShift) {
- final int elementState = getElementState(mMode, isSymbols, isShift);
- final int xmlId = mElementKeyboards.get(elementState);
- final boolean hasShortcutKey = mVoiceKeyEnabled && (isSymbols != mVoiceKeyOnMain);
- return new KeyboardId(xmlId, elementState, mLocale, mConf.orientation,
- mMetrics.widthPixels, mMode, mEditorInfo, mSettingsKeyEnabled, mNoSettingsKey,
- mVoiceKeyEnabled, hasShortcutKey);
+ // TODO: Move this method to KeyboardSet
+ static KeyboardId getKeyboardId(int elementState, boolean isSymbols, Params params) {
+ final boolean hasShortcutKey = params.mVoiceKeyEnabled
+ && (isSymbols != params.mVoiceKeyOnMain);
+ return new KeyboardId(elementState, params.mLocale, params.mOrientation, params.mWidth,
+ params.mMode, params.mInputType, params.mImeOptions, params.mSettingsKeyEnabled,
+ params.mNoSettingsKey, params.mVoiceKeyEnabled, hasShortcutKey);
}
- private static int getElementState(int mode, boolean isSymbols, boolean isShift) {
+ // TODO: Move this method to KeyboardSet
+ static int getElementState(int mode, boolean isSymbols, boolean isShift) {
switch (mode) {
case KeyboardId.MODE_PHONE:
return (isSymbols && isShift)
@@ -198,7 +283,7 @@ public class KeyboardSet {
R.styleable.KeyboardSet_Element_elementName, 0);
final int elementKeyboard = a.getResourceId(
R.styleable.KeyboardSet_Element_elementKeyboard, 0);
- mElementKeyboards.put(elementName, elementKeyboard);
+ mParams.mElementKeyboards.put(elementName, elementKeyboard);
} finally {
a.recycle();
}
@@ -208,7 +293,8 @@ public class KeyboardSet {
public static String parseKeyboardLocale(Resources res, int resId)
throws XmlPullParserException, IOException {
final XmlPullParser parser = res.getXml(resId);
- if (parser == null) return "";
+ if (parser == null)
+ return "";
int event;
while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (event == XmlPullParser.START_TAG) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 3d4a6efcd..e839fe7a3 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -31,21 +31,15 @@ import com.android.inputmethod.keyboard.internal.KeyboardState;
import com.android.inputmethod.latin.InputView;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.LocaleUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.Settings;
import com.android.inputmethod.latin.SettingsValues;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.Utils;
-import java.lang.ref.SoftReference;
-import java.util.HashMap;
-import java.util.Locale;
-
public class KeyboardSwitcher implements KeyboardState.SwitchActions,
SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
- private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG;
public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916";
private static final int[] KEYBOARD_THEMES = {
@@ -69,9 +63,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
private KeyboardSet mKeyboardSet;
- private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
- new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
-
/** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
* what user actually typed. */
private boolean mIsAutoCorrectionActive;
@@ -121,25 +112,27 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
if (mThemeIndex != themeIndex) {
mThemeIndex = themeIndex;
mThemeContext = new ContextThemeWrapper(context, KEYBOARD_THEMES[themeIndex]);
- mKeyboardCache.clear();
+ KeyboardSet.clearKeyboardCache();
}
}
public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) {
+ mKeyboardSet = new KeyboardSet.Builder(mThemeContext, editorInfo, settingsValues)
+ .build();
+ final KeyboardId mainKeyboardId = mKeyboardSet.getMainKeyboardId();
try {
- mKeyboardSet = new KeyboardSet.Builder(mInputMethodService, editorInfo, settingsValues)
- .build();
mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols),
hasDistinctMultitouch());
- // TODO: Should get rid of this special case handling for Phone Number layouts once we
- // have separate layouts with unique KeyboardIds for alphabet and alphabet-shifted
- // respectively.
- if (mKeyboardSet.mAlphabetId.isPhoneKeyboard()) {
- mState.onToggleAlphabetAndSymbols();
- }
} catch (RuntimeException e) {
- Log.w(TAG, "loading keyboard failed: " + mKeyboardSet.mAlphabetId, e);
- LatinImeLogger.logOnException(mKeyboardSet.mAlphabetId.toString(), e);
+ Log.w(TAG, "loading keyboard failed: " + mainKeyboardId, e);
+ LatinImeLogger.logOnException(mainKeyboardId.toString(), e);
+ return;
+ }
+ // TODO: Should get rid of this special case handling for Phone Number layouts once we
+ // have separate layouts with unique KeyboardIds for alphabet and alphabet-shifted
+ // respectively.
+ if (mainKeyboardId.isPhoneKeyboard()) {
+ mState.onToggleAlphabetAndSymbols();
}
}
@@ -164,58 +157,21 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
mKeyboardView.setKeyPreviewPopupEnabled(
SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources),
SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources));
+ mKeyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive);
+ // If the cached keyboard had been switched to another keyboard while the language was
+ // displayed on its spacebar, it might have had arbitrary text fade factor. In such
+ // case, we should reset the text fade factor. It is also applicable to shortcut key.
+ mKeyboardView.updateSpacebar(0.0f,
+ mSubtypeSwitcher.needsToDisplayLanguage(keyboard.mId.mLocale));
+ mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady());
+ updateShiftState();
final boolean localeChanged = (oldKeyboard == null)
|| !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
- if (keyboard instanceof LatinKeyboard) {
- final LatinKeyboard latinKeyboard = (LatinKeyboard)keyboard;
- latinKeyboard.updateAutoCorrectionState(mIsAutoCorrectionActive);
- // If the cached keyboard had been switched to another keyboard while the language was
- // displayed on its spacebar, it might have had arbitrary text fade factor. In such
- // case, we should reset the text fade factor. It is also applicable to shortcut key.
- latinKeyboard.updateSpacebarLanguage(0.0f,
- Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */),
- mSubtypeSwitcher.needsToDisplayLanguage(latinKeyboard.mId.mLocale));
- latinKeyboard.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady());
- }
- updateShiftState();
mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
}
- // TODO: Move this method to KeyboardSet.
- private LatinKeyboard getKeyboard(Context context, KeyboardId id) {
- final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
- LatinKeyboard keyboard = (ref == null) ? null : ref.get();
- if (keyboard == null) {
- final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, id.mLocale);
- try {
- final LatinKeyboard.Builder builder = new LatinKeyboard.Builder(context);
- builder.load(id);
- builder.setTouchPositionCorrectionEnabled(
- mSubtypeSwitcher.currentSubtypeContainsExtraValueKey(
- LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION));
- keyboard = builder.build();
- } finally {
- LocaleUtils.setSystemLocale(mResources, savedLocale);
- }
- mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
-
- if (DEBUG_CACHE) {
- Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
- + ((ref == null) ? "LOAD" : "GCed") + " id=" + id
- + " theme=" + themeName(keyboard.mThemeId));
- }
- } else if (DEBUG_CACHE) {
- Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id
- + " theme=" + themeName(keyboard.mThemeId));
- }
-
- keyboard.setShiftLocked(false);
- keyboard.setShifted(false);
- return keyboard;
- }
-
public boolean isAlphabetMode() {
- final Keyboard keyboard = getLatinKeyboard();
+ final Keyboard keyboard = getKeyboard();
return keyboard != null && keyboard.mId.isAlphabetKeyboard();
}
@@ -224,12 +180,12 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
}
public boolean isShiftedOrShiftLocked() {
- final Keyboard keyboard = getLatinKeyboard();
+ final Keyboard keyboard = getKeyboard();
return keyboard != null && keyboard.isShiftedOrShiftLocked();
}
public boolean isManualTemporaryUpperCase() {
- final Keyboard keyboard = getLatinKeyboard();
+ final Keyboard keyboard = getKeyboard();
return keyboard != null && keyboard.isManualTemporaryUpperCase();
}
@@ -239,11 +195,9 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
return false;
}
- public LatinKeyboard getLatinKeyboard() {
+ public Keyboard getKeyboard() {
if (mKeyboardView != null) {
- final Keyboard keyboard = mKeyboardView.getKeyboard();
- if (keyboard instanceof LatinKeyboard)
- return (LatinKeyboard)keyboard;
+ return mKeyboardView.getKeyboard();
}
return null;
}
@@ -252,11 +206,11 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
@Override
public void setShifted(int shiftMode) {
mInputMethodService.mHandler.cancelUpdateShiftState();
- LatinKeyboard latinKeyboard = getLatinKeyboard();
- if (latinKeyboard == null)
+ Keyboard keyboard = getKeyboard();
+ if (keyboard == null)
return;
if (shiftMode == AUTOMATIC_SHIFT) {
- latinKeyboard.setAutomaticTemporaryUpperCase();
+ keyboard.setAutomaticTemporaryUpperCase();
} else {
final boolean shifted = (shiftMode == MANUAL_SHIFT);
// On non-distinct multi touch panel device, we should also turn off the shift locked
@@ -264,9 +218,9 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
// On the other hand, on distinct multi touch panel device, turning off the shift
// locked state with shift key pressing is handled by onReleaseShift().
if (!hasDistinctMultitouch() && !shifted && mState.isShiftLocked()) {
- latinKeyboard.setShiftLocked(false);
+ keyboard.setShiftLocked(false);
}
- latinKeyboard.setShifted(shifted);
+ keyboard.setShifted(shifted);
}
mKeyboardView.invalidateAllKeys();
}
@@ -275,10 +229,10 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
@Override
public void setShiftLocked(boolean shiftLocked) {
mInputMethodService.mHandler.cancelUpdateShiftState();
- LatinKeyboard latinKeyboard = getLatinKeyboard();
- if (latinKeyboard == null)
+ Keyboard keyboard = getKeyboard();
+ if (keyboard == null)
return;
- latinKeyboard.setShiftLocked(shiftLocked);
+ keyboard.setShiftLocked(shiftLocked);
mKeyboardView.invalidateAllKeys();
if (!shiftLocked) {
// To be able to turn off caps lock by "double tap" on shift key, we should ignore
@@ -343,25 +297,19 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setSymbolsKeyboard() {
- setKeyboard(getKeyboard(mThemeContext, mKeyboardSet.mSymbolsId));
+ setKeyboard(mKeyboardSet.getSymbolsKeyboard());
}
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setAlphabetKeyboard() {
- setKeyboard(getKeyboard(mThemeContext, mKeyboardSet.mAlphabetId));
+ setKeyboard(mKeyboardSet.getMainKeyboard());
}
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setSymbolsShiftedKeyboard() {
- final Keyboard keyboard = getKeyboard(mThemeContext, mKeyboardSet.mSymbolsShiftedId);
- setKeyboard(keyboard);
- // TODO: Remove this logic once we introduce initial keyboard shift state attribute.
- // Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a.
- // sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked()
- // that takes care of the current keyboard having such shift key or not.
- keyboard.setShiftLocked(keyboard.hasShiftLockKey());
+ setKeyboard(mKeyboardSet.getSymbolsShiftedKeyboard());
}
public boolean isInMomentarySwitchState() {
@@ -457,24 +405,16 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
}
public void onNetworkStateChanged() {
- final LatinKeyboard keyboard = getLatinKeyboard();
- if (keyboard == null) return;
- final Key updatedKey = keyboard.updateShortcutKey(
- SubtypeSwitcher.getInstance().isShortcutImeReady());
- if (updatedKey != null && mKeyboardView != null) {
- mKeyboardView.invalidateKey(updatedKey);
+ if (mKeyboardView != null) {
+ mKeyboardView.updateShortcutKey(SubtypeSwitcher.getInstance().isShortcutImeReady());
}
}
public void onAutoCorrectionStateChanged(boolean isAutoCorrection) {
if (mIsAutoCorrectionActive != isAutoCorrection) {
mIsAutoCorrectionActive = isAutoCorrection;
- final LatinKeyboard keyboard = getLatinKeyboard();
- if (keyboard != null && keyboard.needsAutoCorrectionSpacebarLed()) {
- final Key invalidatedKey = keyboard.updateAutoCorrectionState(isAutoCorrection);
- final LatinKeyboardView keyboardView = getKeyboardView();
- if (keyboardView != null)
- keyboardView.invalidateKey(invalidatedKey);
+ if (mKeyboardView != null) {
+ mKeyboardView.updateAutoCorrectionState(isAutoCorrection);
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index d2741edec..a174fd98f 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -194,7 +194,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
- private static class KeyDrawParams {
+ /* package */ static class KeyDrawParams {
// XML attributes
public final int mKeyTextColor;
public final int mKeyTextInactivatedColor;
@@ -283,7 +283,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
- protected static class KeyPreviewDrawParams {
+ /* package */ static class KeyPreviewDrawParams {
// XML attributes.
public final Drawable mPreviewBackground;
public final Drawable mPreviewLeftBackground;
@@ -474,7 +474,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
if (mKeyboard == null) return;
- final boolean isManualTemporaryUpperCase = mKeyboard.isManualTemporaryUpperCase();
final KeyDrawParams params = mKeyDrawParams;
if (mInvalidatedKey != null && mInvalidatedKeyRect.contains(mDirtyRect)) {
// Draw a single key.
@@ -482,8 +481,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
+ getPaddingLeft();
final int keyDrawY = mInvalidatedKey.mY + getPaddingTop();
canvas.translate(keyDrawX, keyDrawY);
- onBufferDrawKey(mInvalidatedKey, mKeyboard, canvas, mPaint, params,
- isManualTemporaryUpperCase);
+ onDrawKey(mInvalidatedKey, canvas, mPaint, params);
canvas.translate(-keyDrawX, -keyDrawY);
} else {
// Draw all keys.
@@ -491,7 +489,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
final int keyDrawX = key.mX + key.mVisualInsetsLeft + getPaddingLeft();
final int keyDrawY = key.mY + getPaddingTop();
canvas.translate(keyDrawX, keyDrawY);
- onBufferDrawKey(key, mKeyboard, canvas, mPaint, params, isManualTemporaryUpperCase);
+ onDrawKey(key, canvas, mPaint, params);
canvas.translate(-keyDrawX, -keyDrawY);
}
}
@@ -514,38 +512,43 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
- private static void onBufferDrawKey(final Key key, final Keyboard keyboard, final Canvas canvas,
- Paint paint, KeyDrawParams params, boolean isManualTemporaryUpperCase) {
- final boolean debugShowAlign = LatinImeLogger.sVISUALDEBUG;
- // Draw key background.
- if (!key.isSpacer()) {
- final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight
- + params.mPadding.left + params.mPadding.right;
- final int bgHeight = key.mHeight + params.mPadding.top + params.mPadding.bottom;
- final int bgX = -params.mPadding.left;
- final int bgY = -params.mPadding.top;
- final int[] drawableState = key.getCurrentDrawableState();
- final Drawable background = params.mKeyBackground;
- background.setState(drawableState);
- final Rect bounds = background.getBounds();
- if (bgWidth != bounds.right || bgHeight != bounds.bottom) {
- background.setBounds(0, 0, bgWidth, bgHeight);
- }
- canvas.translate(bgX, bgY);
- background.draw(canvas);
- if (debugShowAlign) {
- drawRectangle(canvas, 0, 0, bgWidth, bgHeight, 0x80c00000, new Paint());
- }
- canvas.translate(-bgX, -bgY);
+ private void onDrawKey(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
+ if (key.isSpacer()) return;
+ onDrawKeyBackground(key, canvas, params);
+ onDrawKeyTopVisuals(key, canvas, paint, params);
+ }
+
+ // Draw key background.
+ /* package */ void onDrawKeyBackground(Key key, Canvas canvas, KeyDrawParams params) {
+ final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight
+ + params.mPadding.left + params.mPadding.right;
+ final int bgHeight = key.mHeight + params.mPadding.top + params.mPadding.bottom;
+ final int bgX = -params.mPadding.left;
+ final int bgY = -params.mPadding.top;
+ final int[] drawableState = key.getCurrentDrawableState();
+ final Drawable background = params.mKeyBackground;
+ background.setState(drawableState);
+ final Rect bounds = background.getBounds();
+ if (bgWidth != bounds.right || bgHeight != bounds.bottom) {
+ background.setBounds(0, 0, bgWidth, bgHeight);
}
+ canvas.translate(bgX, bgY);
+ background.draw(canvas);
+ if (LatinImeLogger.sVISUALDEBUG) {
+ drawRectangle(canvas, 0, 0, bgWidth, bgHeight, 0x80c00000, new Paint());
+ }
+ canvas.translate(-bgX, -bgY);
+ }
- // Draw key top visuals.
+ // Draw key top visuals.
+ /* package */ void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint,
+ KeyDrawParams params) {
final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
final int keyHeight = key.mHeight;
final float centerX = keyWidth * 0.5f;
final float centerY = keyHeight * 0.5f;
- if (debugShowAlign) {
+ if (LatinImeLogger.sVISUALDEBUG) {
drawRectangle(canvas, 0, 0, keyWidth, keyHeight, 0x800000c0, new Paint());
}
@@ -554,7 +557,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
float positionX = centerX;
if (key.mLabel != null) {
// Switch the character to uppercase if shift is pressed
- final CharSequence label = keyboard.adjustLabelCase(key.mLabel);
+ final CharSequence label = mKeyboard.adjustLabelCase(key.mLabel);
// For characters, use large font. For labels like "Done", use smaller font.
paint.setTypeface(key.selectTypeface(params.mKeyTextStyle));
final int labelSize = key.selectTextSize(params.mKeyLetterSize,
@@ -597,7 +600,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
Math.min(1.0f, (keyWidth * MAX_LABEL_RATIO) / getLabelWidth(label, paint)));
}
- if (key.hasUppercaseLetter() && isManualTemporaryUpperCase) {
+ if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) {
paint.setColor(params.mKeyTextInactivatedColor);
} else {
paint.setColor(params.mKeyTextColor);
@@ -627,7 +630,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
- if (debugShowAlign) {
+ if (LatinImeLogger.sVISUALDEBUG) {
final Paint line = new Paint();
drawHorizontalLine(canvas, baseline, keyWidth, 0xc0008000, line);
drawVerticalLine(canvas, positionX, keyHeight, 0xc0800080, line);
@@ -644,7 +647,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
hintSize = params.mKeyHintLabelSize;
paint.setTypeface(Typeface.DEFAULT);
} else if (key.hasUppercaseLetter()) {
- hintColor = isManualTemporaryUpperCase
+ hintColor = mKeyboard.isManualTemporaryUpperCase()
? params.mKeyUppercaseLetterActivatedColor
: params.mKeyUppercaseLetterInactivatedColor;
hintSize = params.mKeyUppercaseLetterSize;
@@ -677,7 +680,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
canvas.drawText(hint, 0, hint.length(), hintX, hintY, paint);
- if (debugShowAlign) {
+ if (LatinImeLogger.sVISUALDEBUG) {
final Paint line = new Paint();
drawHorizontalLine(canvas, (int)hintY, keyWidth, 0xc0808000, line);
drawVerticalLine(canvas, (int)hintX, keyHeight, 0xc0808000, line);
@@ -702,29 +705,35 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
drawIcon(canvas, icon, iconX, iconY, iconWidth, iconHeight);
- if (debugShowAlign) {
+ if (LatinImeLogger.sVISUALDEBUG) {
final Paint line = new Paint();
drawVerticalLine(canvas, alignX, keyHeight, 0xc0800080, line);
drawRectangle(canvas, iconX, iconY, iconWidth, iconHeight, 0x80c00000, line);
}
}
- // Draw popup hint "..." at the bottom right corner of the key.
- if ((key.hasPopupHint() && key.mMoreKeys != null && key.mMoreKeys.length > 0)
- || key.needsSpecialPopupHint()) {
- paint.setTextSize(params.mKeyHintLetterSize);
- paint.setColor(params.mKeyHintLabelColor);
- paint.setTextAlign(Align.CENTER);
- final float hintX = keyWidth - params.mKeyHintLetterPadding
- - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2;
- final float hintY = keyHeight - params.mKeyPopupHintLetterPadding;
- canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint);
+ if (key.hasPopupHint() && key.mMoreKeys != null && key.mMoreKeys.length > 0) {
+ drawKeyPopupHint(key, canvas, paint, params);
+ }
+ }
+
+ // Draw popup hint "..." at the bottom right corner of the key.
+ /* package */ void drawKeyPopupHint(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
+ final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
+ final int keyHeight = key.mHeight;
- if (debugShowAlign) {
- final Paint line = new Paint();
- drawHorizontalLine(canvas, (int)hintY, keyWidth, 0xc0808000, line);
- drawVerticalLine(canvas, (int)hintX, keyHeight, 0xc0808000, line);
- }
+ paint.setTextSize(params.mKeyHintLetterSize);
+ paint.setColor(params.mKeyHintLabelColor);
+ paint.setTextAlign(Align.CENTER);
+ final float hintX = keyWidth - params.mKeyHintLetterPadding
+ - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2;
+ final float hintY = keyHeight - params.mKeyPopupHintLetterPadding;
+ canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint);
+
+ if (LatinImeLogger.sVISUALDEBUG) {
+ final Paint line = new Paint();
+ drawHorizontalLine(canvas, (int)hintY, keyWidth, 0xc0808000, line);
+ drawVerticalLine(canvas, (int)hintX, keyHeight, 0xc0808000, line);
}
}
@@ -889,7 +898,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
previewText.setText(mKeyboard.adjustLabelCase(key.mLabel));
} else {
- final Drawable previewIcon = key.getPreviewIcon();
+ final Drawable previewIcon = key.mPreviewIcon;
previewText.setCompoundDrawables(null, null, null,
previewIcon != null ? previewIcon : key.getIcon());
previewText.setText(null);
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
deleted file mode 100644
index abb96f0bb..000000000
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.keyboard;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.Resources.Theme;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
-import com.android.inputmethod.keyboard.internal.KeyboardParams;
-import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.Utils;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Locale;
-
-// TODO: We should remove this class
-public class LatinKeyboard extends Keyboard {
- private static final int SPACE_LED_LENGTH_PERCENT = 80;
-
- private final Resources mRes;
- private final Theme mTheme;
-
- /* Space key and its icons, drawables and colors. */
- private final Key mSpaceKey;
- private final Drawable mSpaceIcon;
- private final boolean mAutoCorrectionSpacebarLedEnabled;
- private final Drawable mAutoCorrectionSpacebarLedIcon;
- private final int mSpacebarTextColor;
- private final int mSpacebarTextShadowColor;
- private final HashMap<Integer, BitmapDrawable> mSpaceDrawableCache =
- new HashMap<Integer, BitmapDrawable>();
- private final boolean mIsSpacebarTriggeringPopupByLongPress;
-
- private boolean mAutoCorrectionSpacebarLedOn;
- private boolean mMultipleEnabledIMEsOrSubtypes;
- private boolean mNeedsToDisplayLanguage;
- private float mSpacebarTextFadeFactor = 0.0f;
-
- /* Shortcut key and its icons if available */
- private final Key mShortcutKey;
- private final Drawable mEnabledShortcutIcon;
- private final Drawable mDisabledShortcutIcon;
-
- // Height in space key the language name will be drawn. (proportional to space key height)
- public static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
- // If the full language name needs to be smaller than this value to be drawn on space key,
- // its short language name will be used instead.
- private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f;
-
- private static final String SMALL_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "small";
- private static final String MEDIUM_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "medium";
-
- private LatinKeyboard(Context context, LatinKeyboardParams params) {
- super(params);
- mRes = context.getResources();
- mTheme = context.getTheme();
-
- // The index of space key is available only after Keyboard constructor has finished.
- mSpaceKey = params.mSpaceKey;
- mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon() : null;
-
- mShortcutKey = params.mShortcutKey;
- mEnabledShortcutIcon = (mShortcutKey != null) ? mShortcutKey.getIcon() : null;
- final int longPressSpaceKeyTimeout =
- mRes.getInteger(R.integer.config_long_press_space_key_timeout);
- mIsSpacebarTriggeringPopupByLongPress = (longPressSpaceKeyTimeout > 0);
-
- final TypedArray a = context.obtainStyledAttributes(
- null, R.styleable.LatinKeyboard, R.attr.latinKeyboardStyle, R.style.LatinKeyboard);
- mAutoCorrectionSpacebarLedEnabled = a.getBoolean(
- R.styleable.LatinKeyboard_autoCorrectionSpacebarLedEnabled, false);
- mAutoCorrectionSpacebarLedIcon = a.getDrawable(
- R.styleable.LatinKeyboard_autoCorrectionSpacebarLedIcon);
- mDisabledShortcutIcon = a.getDrawable(R.styleable.LatinKeyboard_disabledShortcutIcon);
- mSpacebarTextColor = a.getColor(R.styleable.LatinKeyboard_spacebarTextColor, 0);
- mSpacebarTextShadowColor = a.getColor(
- R.styleable.LatinKeyboard_spacebarTextShadowColor, 0);
- a.recycle();
- }
-
- private static class LatinKeyboardParams extends KeyboardParams {
- public Key mSpaceKey = null;
- public Key mShortcutKey = null;
-
- @Override
- public void onAddKey(Key key) {
- super.onAddKey(key);
-
- switch (key.mCode) {
- case Keyboard.CODE_SPACE:
- mSpaceKey = key;
- break;
- case Keyboard.CODE_SHORTCUT:
- mShortcutKey = key;
- break;
- }
- }
- }
-
- public static class Builder extends KeyboardBuilder<LatinKeyboardParams> {
- public Builder(Context context) {
- super(context, new LatinKeyboardParams());
- }
-
- @Override
- public Builder load(KeyboardId id) {
- super.load(id);
- return this;
- }
-
- @Override
- public LatinKeyboard build() {
- return new LatinKeyboard(mContext, mParams);
- }
- }
-
- public Key updateSpacebarLanguage(float fadeFactor, boolean multipleEnabledIMEsOrSubtypes,
- boolean needsToDisplayLanguage) {
- mSpacebarTextFadeFactor = fadeFactor;
- mMultipleEnabledIMEsOrSubtypes = multipleEnabledIMEsOrSubtypes;
- mNeedsToDisplayLanguage = needsToDisplayLanguage;
- updateSpacebarIcon();
- return mSpaceKey;
- }
-
- private static int getSpacebarTextColor(int color, float fadeFactor) {
- final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor),
- Color.red(color), Color.green(color), Color.blue(color));
- return newColor;
- }
-
- public Key updateShortcutKey(boolean available) {
- if (mShortcutKey == null)
- return null;
- mShortcutKey.setEnabled(available);
- mShortcutKey.setIcon(available ? mEnabledShortcutIcon : mDisabledShortcutIcon);
- return mShortcutKey;
- }
-
- public boolean needsAutoCorrectionSpacebarLed() {
- return mAutoCorrectionSpacebarLedEnabled;
- }
-
- /**
- * @return a key which should be invalidated.
- */
- public Key updateAutoCorrectionState(boolean isAutoCorrection) {
- mAutoCorrectionSpacebarLedOn = isAutoCorrection;
- updateSpacebarIcon();
- return mSpaceKey;
- }
-
- @Override
- public CharSequence adjustLabelCase(CharSequence label) {
- if (mId.isAlphabetKeyboard() && isShiftedOrShiftLocked() && !TextUtils.isEmpty(label)
- && label.length() < 3 && Character.isLowerCase(label.charAt(0))) {
- return label.toString().toUpperCase(mId.mLocale);
- }
- return label;
- }
-
- private void updateSpacebarIcon() {
- if (mSpaceKey == null) return;
- final boolean shouldShowInputMethodPicker = mIsSpacebarTriggeringPopupByLongPress
- && mMultipleEnabledIMEsOrSubtypes;
- mSpaceKey.setNeedsSpecialPopupHint(shouldShowInputMethodPicker);
- if (mNeedsToDisplayLanguage) {
- mSpaceKey.setIcon(getSpaceDrawable(mId.mLocale));
- } else if (mAutoCorrectionSpacebarLedOn) {
- mSpaceKey.setIcon(getSpaceDrawable(null));
- } else {
- mSpaceKey.setIcon(mSpaceIcon);
- }
- }
-
- // Compute width of text with specified text size using paint.
- private static int getTextWidth(Paint paint, String text, float textSize, Rect bounds) {
- paint.setTextSize(textSize);
- paint.getTextBounds(text, 0, text.length(), bounds);
- return bounds.width();
- }
-
- // Layout local language name and left and right arrow on spacebar.
- private static String layoutSpacebar(Paint paint, Locale locale, int width,
- float origTextSize) {
- final Rect bounds = new Rect();
-
- // Estimate appropriate language name text size to fit in maxTextWidth.
- String language = Utils.getFullDisplayName(locale, true);
- int textWidth = getTextWidth(paint, language, origTextSize, bounds);
- // Assuming text width and text size are proportional to each other.
- float textSize = origTextSize * Math.min(width / textWidth, 1.0f);
- // allow variable text size
- textWidth = getTextWidth(paint, language, textSize, bounds);
- // If text size goes too small or text does not fit, use middle or short name
- final boolean useMiddleName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
- || (textWidth > width);
-
- final boolean useShortName;
- if (useMiddleName) {
- language = Utils.getMiddleDisplayLanguage(locale);
- textWidth = getTextWidth(paint, language, origTextSize, bounds);
- textSize = origTextSize * Math.min(width / textWidth, 1.0f);
- useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
- || (textWidth > width);
- } else {
- useShortName = false;
- }
-
- if (useShortName) {
- language = Utils.getShortDisplayLanguage(locale);
- textWidth = getTextWidth(paint, language, origTextSize, bounds);
- textSize = origTextSize * Math.min(width / textWidth, 1.0f);
- }
- paint.setTextSize(textSize);
-
- return language;
- }
-
- private BitmapDrawable getSpaceDrawable(Locale locale) {
- final Integer hashCode = Arrays.hashCode(
- new Object[] { locale, mAutoCorrectionSpacebarLedOn, mSpacebarTextFadeFactor });
- final BitmapDrawable cached = mSpaceDrawableCache.get(hashCode);
- if (cached != null) {
- return cached;
- }
- final BitmapDrawable drawable = new BitmapDrawable(mRes, drawSpacebar(
- locale, mAutoCorrectionSpacebarLedOn, mSpacebarTextFadeFactor));
- mSpaceDrawableCache.put(hashCode, drawable);
- return drawable;
- }
-
- private Bitmap drawSpacebar(Locale inputLocale, boolean isAutoCorrection,
- float textFadeFactor) {
- final int width = mSpaceKey.mWidth;
- final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight;
- final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(buffer);
- final Resources res = mRes;
- canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
-
- // If application locales are explicitly selected.
- if (inputLocale != null) {
- final Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setTextAlign(Align.CENTER);
-
- final String textSizeOfLanguageOnSpacebar = res.getString(
- R.string.config_text_size_of_language_on_spacebar,
- SMALL_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR);
- final int textStyle;
- final int defaultTextSize;
- if (MEDIUM_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR.equals(textSizeOfLanguageOnSpacebar)) {
- textStyle = android.R.style.TextAppearance_Medium;
- defaultTextSize = 18;
- } else {
- textStyle = android.R.style.TextAppearance_Small;
- defaultTextSize = 14;
- }
-
- final String language = layoutSpacebar(paint, inputLocale, width, getTextSizeFromTheme(
- mTheme, textStyle, defaultTextSize));
-
- // Draw language text with shadow
- // In case there is no space icon, we will place the language text at the center of
- // spacebar.
- final float descent = paint.descent();
- final float textHeight = -paint.ascent() + descent;
- final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE
- : height / 2 + textHeight / 2;
- paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, textFadeFactor));
- canvas.drawText(language, width / 2, baseline - descent - 1, paint);
- paint.setColor(getSpacebarTextColor(mSpacebarTextColor, textFadeFactor));
- canvas.drawText(language, width / 2, baseline - descent, paint);
- }
-
- // Draw the spacebar icon at the bottom
- if (isAutoCorrection) {
- final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100;
- final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight();
- int x = (width - iconWidth) / 2;
- int y = height - iconHeight;
- mAutoCorrectionSpacebarLedIcon.setBounds(x, y, x + iconWidth, y + iconHeight);
- mAutoCorrectionSpacebarLedIcon.draw(canvas);
- } else if (mSpaceIcon != null) {
- final int iconWidth = mSpaceIcon.getIntrinsicWidth();
- final int iconHeight = mSpaceIcon.getIntrinsicHeight();
- int x = (width - iconWidth) / 2;
- int y = height - iconHeight;
- mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight);
- mSpaceIcon.draw(canvas);
- }
- return buffer;
- }
-
- @Override
- public int[] getNearestKeys(int x, int y) {
- // Avoid dead pixels at edges of the keyboard
- return super.getNearestKeys(Math.max(0, Math.min(x, mOccupiedWidth - 1)),
- Math.max(0, Math.min(y, mOccupiedHeight - 1)));
- }
-
- private static final int[] ATTR_TEXT_SIZE = { android.R.attr.textSize };
-
- public static int getTextSizeFromTheme(Theme theme, int style, int defValue) {
- final TypedArray a = theme.obtainStyledAttributes(style, ATTR_TEXT_SIZE);
- final int textSize = a.getDimensionPixelSize(a.getResourceId(0, 0), defValue);
- a.recycle();
- return textSize;
- }
-}
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 376f4c7c3..3433cd455 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -19,8 +19,18 @@ package com.android.inputmethod.keyboard;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Message;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
@@ -38,10 +48,15 @@ import com.android.inputmethod.deprecated.VoiceProxy;
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.Utils;
+import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Locale;
import java.util.WeakHashMap;
/**
@@ -57,11 +72,39 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true;
+ /* Space key and its icons, drawables and colors. */
+ private Key mSpaceKey;
+ private Drawable mSpaceIcon;
+ private final boolean mIsSpacebarTriggeringPopupByLongPress;
+ private static final int SPACE_LED_LENGTH_PERCENT = 80;
+ private final boolean mAutoCorrectionSpacebarLedEnabled;
+ private final Drawable mAutoCorrectionSpacebarLedIcon;
+ private final float mSpacebarTextRatio;
+ private float mSpacebarTextSize;
+ private final int mSpacebarTextColor;
+ private final int mSpacebarTextShadowColor;
+ private final HashMap<Integer, BitmapDrawable> mSpacebarDrawableCache =
+ new HashMap<Integer, BitmapDrawable>();
+
+ private boolean mAutoCorrectionSpacebarLedOn;
+ private boolean mNeedsToDisplayLanguage;
+ private Locale mSpacebarLocale;
+ private float mSpacebarTextFadeFactor = 0.0f;
+
+ // Height in space key the language name will be drawn. (proportional to space key height)
+ public static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
+ // If the full language name needs to be smaller than this value to be drawn on space key,
+ // its short language name will be used instead.
+ private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f;
+
private final SuddenJumpingTouchEventHandler mTouchScreenRegulator;
// Timing constants
private final int mKeyRepeatInterval;
+ // TODO: Kill process when the usability study mode was changed.
+ private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy;
+
// Mini keyboard
private PopupWindow mMoreKeysWindow;
private MoreKeysPanel mMoreKeysPanel;
@@ -176,8 +219,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
@Override
public boolean onDoubleTap(MotionEvent firstDown) {
final Keyboard keyboard = getKeyboard();
- if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard instanceof LatinKeyboard
- && ((LatinKeyboard) keyboard).mId.isAlphabetKeyboard()) {
+ if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard.mId.isAlphabetKeyboard()) {
final int pointerIndex = firstDown.getActionIndex();
final int id = firstDown.getPointerId(pointerIndex);
final PointerTracker tracker = getPointerTracker(id);
@@ -206,7 +248,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
// Detected a double tap on shift key. If we are in the ignoring double tap
// mode, it means we have already turned off caps lock in
// {@link KeyboardSwitcher#onReleaseShift} .
- onDoubleTapShiftKey(tracker, mKeyTimerHandler.isIgnoringDoubleTap());
+ onDoubleTapShiftKey(mKeyTimerHandler.isIgnoringDoubleTap());
return true;
}
// Otherwise these events should not be handled as double tap.
@@ -217,7 +259,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
}
public LatinKeyboardView(Context context, AttributeSet attrs) {
- this(context, attrs, R.attr.keyboardViewStyle);
+ this(context, attrs, R.attr.latinKeyboardViewStyle);
}
public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) {
@@ -241,6 +283,23 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
PointerTracker.init(mHasDistinctMultitouch, getContext());
+
+ final int longPressSpaceKeyTimeout =
+ res.getInteger(R.integer.config_long_press_space_key_timeout);
+ mIsSpacebarTriggeringPopupByLongPress = (longPressSpaceKeyTimeout > 0);
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.LatinKeyboardView, defStyle, R.style.LatinKeyboardView);
+ mAutoCorrectionSpacebarLedEnabled = a.getBoolean(
+ R.styleable.LatinKeyboardView_autoCorrectionSpacebarLedEnabled, false);
+ mAutoCorrectionSpacebarLedIcon = a.getDrawable(
+ R.styleable.LatinKeyboardView_autoCorrectionSpacebarLedIcon);
+ mSpacebarTextRatio = a.getFraction(R.styleable.LatinKeyboardView_spacebarTextRatio,
+ 1000, 1000, 1) / 1000.0f;
+ mSpacebarTextColor = a.getColor(R.styleable.LatinKeyboardView_spacebarTextColor, 0);
+ mSpacebarTextShadowColor = a.getColor(
+ R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0);
+ a.recycle();
}
public void startIgnoringDoubleTap() {
@@ -295,6 +354,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
PointerTracker.setKeyDetector(mKeyDetector);
mTouchScreenRegulator.setKeyboard(keyboard);
mMoreKeysPanelCache.clear();
+
+ mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE);
+ mSpaceIcon = keyboard.mIconsSet.getIconByAttrId(R.styleable.Keyboard_iconSpaceKey);
+ final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
+ mSpacebarTextSize = keyHeight * mSpacebarTextRatio;
+ mSpacebarLocale = keyboard.mId.mLocale;
+ clearSpacebarDrawableCache();
}
/**
@@ -342,8 +408,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
return onLongPress(parentKey, tracker);
}
- private void onDoubleTapShiftKey(@SuppressWarnings("unused") PointerTracker tracker,
- final boolean ignore) {
+ private void onDoubleTapShiftKey(final boolean ignore) {
// When shift key is double tapped, the first tap is correctly processed as usual tap. And
// the second tap is treated as this double tap event, so that we need not mark tracker
// calling setAlreadyProcessed() nor remove the tracker from mPointerQueue.
@@ -385,29 +450,26 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
protected boolean onLongPress(Key parentKey, PointerTracker tracker) {
final int primaryCode = parentKey.mCode;
final Keyboard keyboard = getKeyboard();
- if (keyboard instanceof LatinKeyboard) {
- final LatinKeyboard latinKeyboard = (LatinKeyboard) keyboard;
- if (primaryCode == Keyboard.CODE_DIGIT0 && latinKeyboard.mId.isPhoneKeyboard()) {
- tracker.onLongPressed();
- // Long pressing on 0 in phone number keypad gives you a '+'.
- invokeCodeInput(Keyboard.CODE_PLUS);
- invokeReleaseKey(primaryCode);
- return true;
- }
- if (primaryCode == Keyboard.CODE_SHIFT && latinKeyboard.mId.isAlphabetKeyboard()) {
+ if (primaryCode == Keyboard.CODE_DIGIT0 && keyboard.mId.isPhoneKeyboard()) {
+ tracker.onLongPressed();
+ // Long pressing on 0 in phone number keypad gives you a '+'.
+ invokeCodeInput(Keyboard.CODE_PLUS);
+ invokeReleaseKey(primaryCode);
+ return true;
+ }
+ if (primaryCode == Keyboard.CODE_SHIFT && keyboard.mId.isAlphabetKeyboard()) {
+ tracker.onLongPressed();
+ invokeCodeInput(Keyboard.CODE_CAPSLOCK);
+ invokeReleaseKey(primaryCode);
+ return true;
+ }
+ if (primaryCode == Keyboard.CODE_SPACE) {
+ // Long pressing the space key invokes IME switcher dialog.
+ if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) {
tracker.onLongPressed();
- invokeCodeInput(Keyboard.CODE_CAPSLOCK);
invokeReleaseKey(primaryCode);
return true;
}
- if (primaryCode == Keyboard.CODE_SPACE) {
- // Long pressing the space key invokes IME switcher dialog.
- if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) {
- tracker.onLongPressed();
- invokeReleaseKey(primaryCode);
- return true;
- }
- }
}
return openMoreKeysPanel(parentKey, tracker);
}
@@ -514,6 +576,33 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
x = (int)me.getX(index);
y = (int)me.getY(index);
}
+ if (ENABLE_USABILITY_STUDY_LOG) {
+ final String eventTag;
+ switch (action) {
+ case MotionEvent.ACTION_UP:
+ eventTag = "[Up]";
+ break;
+ case MotionEvent.ACTION_DOWN:
+ eventTag = "[Down]";
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ eventTag = "[PointerUp]";
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ eventTag = "[PointerDown]";
+ break;
+ case MotionEvent.ACTION_MOVE: // Skip this as being logged below
+ eventTag = "";
+ break;
+ default:
+ eventTag = "[Action" + action + "]";
+ break;
+ }
+ if (!TextUtils.isEmpty(eventTag)) {
+ UsabilityStudyLogUtils.getInstance().write(
+ eventTag + eventTime + "," + id + "," + x + "," + y + "\t\t");
+ }
+ }
if (mKeyTimerHandler.isInKeyRepeat()) {
final PointerTracker tracker = getPointerTracker(id);
@@ -570,6 +659,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
py = (int)me.getY(i);
}
tracker.onMoveEvent(px, py, eventTime);
+ if (ENABLE_USABILITY_STUDY_LOG) {
+ UsabilityStudyLogUtils.getInstance().write("[Move]" + eventTime + ","
+ + me.getPointerId(i) + "," + px + "," + py + "\t\t");
+ }
}
} else {
getPointerTracker(id).processMotionEvent(action, x, y, eventTime, this);
@@ -624,9 +717,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
- final PointerTracker tracker = getPointerTracker(0);
return AccessibleKeyboardViewProxy.getInstance().dispatchPopulateAccessibilityEvent(
- event, tracker) || super.dispatchPopulateAccessibilityEvent(event);
+ event) || super.dispatchPopulateAccessibilityEvent(event);
}
return super.dispatchPopulateAccessibilityEvent(event);
@@ -650,4 +742,180 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
// Reflection doesn't support calling superclass methods.
return false;
}
+
+ public void updateShortcutKey(boolean available) {
+ final Keyboard keyboard = getKeyboard();
+ if (keyboard == null) return;
+ final Key shortcutKey = keyboard.getKey(Keyboard.CODE_SHORTCUT);
+ if (shortcutKey == null) return;
+ shortcutKey.setEnabled(available);
+ invalidateKey(shortcutKey);
+ }
+
+ public void updateSpacebar(float fadeFactor, boolean needsToDisplayLanguage) {
+ mSpacebarTextFadeFactor = fadeFactor;
+ mNeedsToDisplayLanguage = needsToDisplayLanguage;
+ updateSpacebarIcon();
+ invalidateKey(mSpaceKey);
+ }
+
+ public void updateAutoCorrectionState(boolean isAutoCorrection) {
+ if (!mAutoCorrectionSpacebarLedEnabled) return;
+ mAutoCorrectionSpacebarLedOn = isAutoCorrection;
+ updateSpacebarIcon();
+ invalidateKey(mSpaceKey);
+ }
+
+ @Override
+ /* package */ void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint,
+ KeyDrawParams params) {
+ super.onDrawKeyTopVisuals(key, canvas, paint, params);
+
+ if (key.mCode == Keyboard.CODE_SPACE) {
+ // Whether space key needs to show the "..." popup hint for special purposes
+ if (mIsSpacebarTriggeringPopupByLongPress
+ && Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
+ super.drawKeyPopupHint(key, canvas, paint, params);
+ }
+ }
+ }
+
+ // TODO: Get rid of this method and draw spacebar locale and auto correction spacebar LED
+ // in onDrawKeyTopVisuals.
+ private void updateSpacebarIcon() {
+ if (mSpaceKey == null) return;
+ if (mNeedsToDisplayLanguage) {
+ mSpaceKey.setIcon(getSpaceDrawable(mSpacebarLocale));
+ } else if (mAutoCorrectionSpacebarLedOn) {
+ mSpaceKey.setIcon(getSpaceDrawable(null));
+ } else {
+ mSpaceKey.setIcon(mSpaceIcon);
+ }
+ }
+
+ private static int getSpacebarTextColor(int color, float fadeFactor) {
+ final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor),
+ Color.red(color), Color.green(color), Color.blue(color));
+ return newColor;
+ }
+
+ // Compute width of text with specified text size using paint.
+ private static int getTextWidth(Paint paint, String text, float textSize, Rect bounds) {
+ paint.setTextSize(textSize);
+ paint.getTextBounds(text, 0, text.length(), bounds);
+ return bounds.width();
+ }
+
+ // Layout local language name and left and right arrow on spacebar.
+ private static String layoutSpacebar(Paint paint, Locale locale, int width,
+ float origTextSize) {
+ final Rect bounds = new Rect();
+
+ // Estimate appropriate language name text size to fit in maxTextWidth.
+ String language = Utils.getFullDisplayName(locale, true);
+ int textWidth = getTextWidth(paint, language, origTextSize, bounds);
+ // Assuming text width and text size are proportional to each other.
+ float textSize = origTextSize * Math.min(width / textWidth, 1.0f);
+ // allow variable text size
+ textWidth = getTextWidth(paint, language, textSize, bounds);
+ // If text size goes too small or text does not fit, use middle or short name
+ final boolean useMiddleName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
+ || (textWidth > width);
+
+ final boolean useShortName;
+ if (useMiddleName) {
+ language = Utils.getMiddleDisplayLanguage(locale);
+ textWidth = getTextWidth(paint, language, origTextSize, bounds);
+ textSize = origTextSize * Math.min(width / textWidth, 1.0f);
+ useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
+ || (textWidth > width);
+ } else {
+ useShortName = false;
+ }
+
+ if (useShortName) {
+ language = Utils.getShortDisplayLanguage(locale);
+ textWidth = getTextWidth(paint, language, origTextSize, bounds);
+ textSize = origTextSize * Math.min(width / textWidth, 1.0f);
+ }
+ paint.setTextSize(textSize);
+
+ return language;
+ }
+
+ private Integer getSpaceDrawableKey(Locale locale) {
+ return Arrays.hashCode(new Object[] {
+ locale,
+ mAutoCorrectionSpacebarLedOn,
+ mSpacebarTextFadeFactor
+ });
+ }
+
+ private void clearSpacebarDrawableCache() {
+ for (final BitmapDrawable drawable : mSpacebarDrawableCache.values()) {
+ final Bitmap bitmap = drawable.getBitmap();
+ bitmap.recycle();
+ }
+ mSpacebarDrawableCache.clear();
+ }
+
+ private BitmapDrawable getSpaceDrawable(Locale locale) {
+ final Integer hashCode = getSpaceDrawableKey(locale);
+ final BitmapDrawable cached = mSpacebarDrawableCache.get(hashCode);
+ if (cached != null) {
+ return cached;
+ }
+ final BitmapDrawable drawable = new BitmapDrawable(getResources(), drawSpacebar(
+ locale, mAutoCorrectionSpacebarLedOn, mSpacebarTextFadeFactor));
+ mSpacebarDrawableCache.put(hashCode, drawable);
+ return drawable;
+ }
+
+ private Bitmap drawSpacebar(Locale inputLocale, boolean isAutoCorrection,
+ float textFadeFactor) {
+ final int width = mSpaceKey.mWidth;
+ final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight;
+ final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(buffer);
+ canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
+
+ // If application locales are explicitly selected.
+ if (inputLocale != null) {
+ final Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setTextAlign(Align.CENTER);
+
+ final String language = layoutSpacebar(paint, inputLocale, width, mSpacebarTextSize);
+
+ // Draw language text with shadow
+ // In case there is no space icon, we will place the language text at the center of
+ // spacebar.
+ final float descent = paint.descent();
+ final float textHeight = -paint.ascent() + descent;
+ final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE
+ : height / 2 + textHeight / 2;
+ paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, textFadeFactor));
+ canvas.drawText(language, width / 2, baseline - descent - 1, paint);
+ paint.setColor(getSpacebarTextColor(mSpacebarTextColor, textFadeFactor));
+ canvas.drawText(language, width / 2, baseline - descent, paint);
+ }
+
+ // Draw the spacebar icon at the bottom
+ if (isAutoCorrection) {
+ final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100;
+ final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight();
+ int x = (width - iconWidth) / 2;
+ int y = height - iconHeight;
+ mAutoCorrectionSpacebarLedIcon.setBounds(x, y, x + iconWidth, y + iconHeight);
+ mAutoCorrectionSpacebarLedIcon.draw(canvas);
+ } else if (mSpaceIcon != null) {
+ final int iconWidth = mSpaceIcon.getIntrinsicWidth();
+ final int iconHeight = mSpaceIcon.getIntrinsicHeight();
+ int x = (width - iconWidth) / 2;
+ int y = height - iconHeight;
+ mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight);
+ mSpaceIcon.draw(canvas);
+ }
+ return buffer;
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
index e0f21a247..548b5ea85 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
@@ -18,8 +18,6 @@ package com.android.inputmethod.keyboard;
import android.graphics.Paint;
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
-import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.keyboard.internal.MoreKeySpecParser;
import com.android.inputmethod.latin.R;
@@ -35,10 +33,10 @@ public class MiniKeyboard extends Keyboard {
return mDefaultKeyCoordX;
}
- public static class Builder extends KeyboardBuilder<Builder.MiniKeyboardParams> {
+ public static class Builder extends Keyboard.Builder<Builder.MiniKeyboardParams> {
private final CharSequence[] mMoreKeys;
- public static class MiniKeyboardParams extends KeyboardParams {
+ public static class MiniKeyboardParams extends Keyboard.Params {
/* package */int mTopRowAdjustment;
public int mNumRows;
public int mNumColumns;
@@ -207,7 +205,7 @@ public class MiniKeyboard extends Keyboard {
public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) {
super(view.getContext(), new MiniKeyboardParams());
- load(parentKeyboard.mId.cloneWithNewXml(xmlId));
+ load(xmlId, parentKeyboard.mId);
// TODO: Mini keyboard's vertical gap is currently calculated heuristically.
// Should revise the algorithm.
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 3a07cdf4d..7c14b5888 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -29,6 +29,7 @@ import com.android.inputmethod.latin.R;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
public class PointerTracker {
private static final String TAG = PointerTracker.class.getSimpleName();
@@ -118,7 +119,7 @@ public class PointerTracker {
private KeyboardActionListener mListener = EMPTY_LISTENER;
private Keyboard mKeyboard;
- private List<Key> mKeys;
+ private Set<Key> mKeys;
private int mKeyQuarterWidthSquared;
private final TextView mKeyPreviewText;
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 778aac3de..c1dae0601 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -18,19 +18,19 @@ package com.android.inputmethod.keyboard;
import android.graphics.Rect;
-import com.android.inputmethod.keyboard.internal.KeyboardParams.TouchPositionCorrection;
+import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection;
import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
+import java.util.Set;
public class ProximityInfo {
public static final int MAX_PROXIMITY_CHARS_SIZE = 16;
/** Number of key widths from current touch point to search for nearest keys. */
private static float SEARCH_DISTANCE = 1.2f;
- private static final int[] EMPTY_INT_ARRAY = new int[0];
+ private static final Key[] EMPTY_KEY_ARRAY = new Key[0];
private final int mKeyHeight;
private final int mGridWidth;
@@ -41,10 +41,10 @@ public class ProximityInfo {
// TODO: Find a proper name for mKeyboardMinWidth
private final int mKeyboardMinWidth;
private final int mKeyboardHeight;
- private final int[][] mGridNeighbors;
+ private final Key[][] mGridNeighbors;
ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth,
- int keyHeight, List<Key> keys, TouchPositionCorrection touchPositionCorrection) {
+ int keyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection) {
mGridWidth = gridWidth;
mGridHeight = gridHeight;
mGridSize = mGridWidth * mGridHeight;
@@ -53,7 +53,7 @@ public class ProximityInfo {
mKeyboardMinWidth = minWidth;
mKeyboardHeight = height;
mKeyHeight = keyHeight;
- mGridNeighbors = new int[mGridSize][];
+ mGridNeighbors = new Key[mGridSize][];
if (minWidth == 0 || height == 0) {
// No proximity required. Keyboard might be mini keyboard.
return;
@@ -62,7 +62,7 @@ public class ProximityInfo {
}
public static ProximityInfo createDummyProximityInfo() {
- return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptyList(), null);
+ return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptySet(), null);
}
public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) {
@@ -86,16 +86,16 @@ public class ProximityInfo {
float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii);
private native void releaseProximityInfoNative(long nativeProximityInfo);
- private final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth,
- int keyboardHeight, List<Key> keys,
+ private final void setProximityInfo(Key[][] gridNeighborKeys, int keyboardWidth,
+ int keyboardHeight, Set<Key> keys,
TouchPositionCorrection touchPositionCorrection) {
- int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
+ final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE);
for (int i = 0; i < mGridSize; ++i) {
- final int proximityCharsLength = gridNeighborKeyIndexes[i].length;
+ final int proximityCharsLength = gridNeighborKeys[i].length;
for (int j = 0; j < proximityCharsLength; ++j) {
proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j] =
- keys.get(gridNeighborKeyIndexes[i][j]).mCode;
+ gridNeighborKeys[i][j].mCode;
}
}
final int keyCount = keys.size();
@@ -104,25 +104,45 @@ public class ProximityInfo {
final int[] keyWidths = new int[keyCount];
final int[] keyHeights = new int[keyCount];
final int[] keyCharCodes = new int[keyCount];
- for (int i = 0; i < keyCount; ++i) {
- final Key key = keys.get(i);
+ final float[] sweetSpotCenterXs;
+ final float[] sweetSpotCenterYs;
+ final float[] sweetSpotRadii;
+ final boolean calculateSweetSpotParams;
+ if (touchPositionCorrection != null && touchPositionCorrection.isValid()) {
+ sweetSpotCenterXs = new float[keyCount];
+ sweetSpotCenterYs = new float[keyCount];
+ sweetSpotRadii = new float[keyCount];
+ calculateSweetSpotParams = true;
+ } else {
+ sweetSpotCenterXs = sweetSpotCenterYs = sweetSpotRadii = null;
+ calculateSweetSpotParams = false;
+ }
+
+ int i = 0;
+ for (final Key key : keys) {
keyXCoordinates[i] = key.mX;
keyYCoordinates[i] = key.mY;
keyWidths[i] = key.mWidth;
keyHeights[i] = key.mHeight;
keyCharCodes[i] = key.mCode;
- }
-
- float[] sweetSpotCenterXs = null;
- float[] sweetSpotCenterYs = null;
- float[] sweetSpotRadii = null;
-
- if (touchPositionCorrection != null && touchPositionCorrection.isValid()) {
- sweetSpotCenterXs = new float[keyCount];
- sweetSpotCenterYs = new float[keyCount];
- sweetSpotRadii = new float[keyCount];
- calculateSweetSpot(keys, touchPositionCorrection,
- sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+ if (calculateSweetSpotParams) {
+ final Rect hitBox = key.mHitBox;
+ final int row = hitBox.top / mKeyHeight;
+ if (row < touchPositionCorrection.mRadii.length) {
+ final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f;
+ final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f;
+ final float hitBoxWidth = hitBox.right - hitBox.left;
+ final float hitBoxHeight = hitBox.bottom - hitBox.top;
+ final float x = touchPositionCorrection.mXs[row];
+ final float y = touchPositionCorrection.mYs[row];
+ final float radius = touchPositionCorrection.mRadii[row];
+ sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
+ sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
+ sweetSpotRadii[i] = radius * (float)Math.sqrt(
+ hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
+ }
+ }
+ i++;
}
mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE,
@@ -131,32 +151,6 @@ public class ProximityInfo {
sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
}
- private void calculateSweetSpot(List<Key> keys, TouchPositionCorrection touchPositionCorrection,
- float[] sweetSpotCenterXs, float[] sweetSpotCenterYs, float[] sweetSpotRadii) {
- final int keyCount = keys.size();
- final float[] xs = touchPositionCorrection.mXs;
- final float[] ys = touchPositionCorrection.mYs;
- final float[] radii = touchPositionCorrection.mRadii;
- for (int i = 0; i < keyCount; ++i) {
- final Key key = keys.get(i);
- final Rect hitBox = key.mHitBox;
- final int row = hitBox.top / mKeyHeight;
- if (row < radii.length) {
- final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f;
- final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f;
- final float hitBoxWidth = hitBox.right - hitBox.left;
- final float hitBoxHeight = hitBox.bottom - hitBox.top;
- final float x = xs[row];
- final float y = ys[row];
- final float radius = radii[row];
- sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
- sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
- sweetSpotRadii[i] = radius
- * (float)Math.sqrt(hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
- }
- }
- }
-
public long getNativeProximityInfo() {
return mNativeProximityInfo;
}
@@ -173,12 +167,12 @@ public class ProximityInfo {
}
}
- private void computeNearestNeighbors(int defaultWidth, List<Key> keys,
+ private void computeNearestNeighbors(int defaultWidth, Set<Key> keys,
TouchPositionCorrection touchPositionCorrection) {
final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE);
final int threshold = thresholdBase * thresholdBase;
// Round-up so we don't have any pixels outside the grid
- final int[] indices = new int[keys.size()];
+ final Key[] neighborKeys = new Key[keys.size()];
final int gridWidth = mGridWidth * mCellWidth;
final int gridHeight = mGridHeight * mCellHeight;
for (int x = 0; x < gridWidth; x += mCellWidth) {
@@ -186,24 +180,23 @@ public class ProximityInfo {
final int centerX = x + mCellWidth / 2;
final int centerY = y + mCellHeight / 2;
int count = 0;
- for (int i = 0; i < keys.size(); i++) {
- final Key key = keys.get(i);
+ for (final Key key : keys) {
if (key.isSpacer()) continue;
- if (key.squaredDistanceToEdge(centerX, centerY) < threshold)
- indices[count++] = i;
+ if (key.squaredDistanceToEdge(centerX, centerY) < threshold) {
+ neighborKeys[count++] = key;
+ }
}
- final int[] cell = new int[count];
- System.arraycopy(indices, 0, cell, 0, count);
- mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = cell;
+ mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] =
+ Arrays.copyOfRange(neighborKeys, 0, count);
}
}
setProximityInfo(mGridNeighbors, mKeyboardMinWidth, mKeyboardHeight, keys,
touchPositionCorrection);
}
- public int[] getNearestKeys(int x, int y) {
+ public Key[] getNearestKeys(int x, int y) {
if (mGridNeighbors == null) {
- return EMPTY_INT_ARRAY;
+ return EMPTY_KEY_ARRAY;
}
if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) {
int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth);
@@ -211,6 +204,6 @@ public class ProximityInfo {
return mGridNeighbors[index];
}
}
- return EMPTY_INT_ARRAY;
+ return EMPTY_KEY_ARRAY;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
index 3324fa6af..5dd8340fc 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
@@ -19,7 +19,9 @@ package com.android.inputmethod.keyboard.internal;
import android.content.res.TypedArray;
import android.util.Log;
+import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.XmlParseUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -159,8 +161,8 @@ public class KeyStyles {
readTextArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags);
readInt(keyAttr, R.styleable.Keyboard_Key_keyIcon);
+ readInt(keyAttr, R.styleable.Keyboard_Key_keyIconDisabled);
readInt(keyAttr, R.styleable.Keyboard_Key_keyIconPreview);
- readInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted);
readInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn);
readInt(keyAttr, R.styleable.Keyboard_Key_backgroundType);
readFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
@@ -197,7 +199,7 @@ public class KeyStyles {
XmlPullParser parser) throws XmlPullParserException {
final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName);
if (DEBUG) Log.d(TAG, String.format("<%s styleName=%s />",
- KeyboardBuilder.TAG_KEY_STYLE, styleName));
+ Keyboard.Builder.TAG_KEY_STYLE, styleName));
if (mStyles.containsKey(styleName))
throw new XmlParseUtils.ParseException(
"duplicate key style declared: " + styleName, parser);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
deleted file mode 100644
index 7382cfa7f..000000000
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ /dev/null
@@ -1,833 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.inputmethod.keyboard.internal;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.TypedValue;
-import android.util.Xml;
-import android.view.InflateException;
-
-import com.android.inputmethod.compat.EditorInfoCompatUtils;
-import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardId;
-import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-/**
- * Keyboard Building helper.
- *
- * This class parses Keyboard XML file and eventually build a Keyboard.
- * The Keyboard XML file looks like:
- * <pre>
- * &gt;!-- xml/keyboard.xml --&lt;
- * &gt;Keyboard keyboard_attributes*&lt;
- * &gt;!-- Keyboard Content --&lt;
- * &gt;Row row_attributes*&lt;
- * &gt;!-- Row Content --&lt;
- * &gt;Key key_attributes* /&lt;
- * &gt;Spacer horizontalGap="0.2in" /&lt;
- * &gt;include keyboardLayout="@xml/other_keys"&lt;
- * ...
- * &gt;/Row&lt;
- * &gt;include keyboardLayout="@xml/other_rows"&lt;
- * ...
- * &gt;/Keyboard&lt;
- * </pre>
- * The XML file which is included in other file must have &gt;merge&lt; as root element, such as:
- * <pre>
- * &gt;!-- xml/other_keys.xml --&lt;
- * &gt;merge&lt;
- * &gt;Key key_attributes* /&lt;
- * ...
- * &gt;/merge&lt;
- * </pre>
- * and
- * <pre>
- * &gt;!-- xml/other_rows.xml --&lt;
- * &gt;merge&lt;
- * &gt;Row row_attributes*&lt;
- * &gt;Key key_attributes* /&lt;
- * &gt;/Row&lt;
- * ...
- * &gt;/merge&lt;
- * </pre>
- * You can also use switch-case-default tags to select Rows and Keys.
- * <pre>
- * &gt;switch&lt;
- * &gt;case case_attribute*&lt;
- * &gt;!-- Any valid tags at switch position --&lt;
- * &gt;/case&lt;
- * ...
- * &gt;default&lt;
- * &gt;!-- Any valid tags at switch position --&lt;
- * &gt;/default&lt;
- * &gt;/switch&lt;
- * </pre>
- * You can declare Key style and specify styles within Key tags.
- * <pre>
- * &gt;switch&lt;
- * &gt;case mode="email"&lt;
- * &gt;key-style styleName="f1-key" parentStyle="modifier-key"
- * keyLabel=".com"
- * /&lt;
- * &gt;/case&lt;
- * &gt;case mode="url"&lt;
- * &gt;key-style styleName="f1-key" parentStyle="modifier-key"
- * keyLabel="http://"
- * /&lt;
- * &gt;/case&lt;
- * &gt;/switch&lt;
- * ...
- * &gt;Key keyStyle="shift-key" ... /&lt;
- * </pre>
- */
-
-public class KeyboardBuilder<KP extends KeyboardParams> {
- private static final String TAG = KeyboardBuilder.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- // Keyboard XML Tags
- private static final String TAG_KEYBOARD = "Keyboard";
- private static final String TAG_ROW = "Row";
- private static final String TAG_KEY = "Key";
- private static final String TAG_SPACER = "Spacer";
- private static final String TAG_INCLUDE = "include";
- private static final String TAG_MERGE = "merge";
- private static final String TAG_SWITCH = "switch";
- private static final String TAG_CASE = "case";
- private static final String TAG_DEFAULT = "default";
- public static final String TAG_KEY_STYLE = "key-style";
-
- private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
- private static final int DEFAULT_KEYBOARD_ROWS = 4;
-
- protected final KP mParams;
- protected final Context mContext;
- protected final Resources mResources;
- private final DisplayMetrics mDisplayMetrics;
-
- private int mCurrentY = 0;
- private Row mCurrentRow = null;
- private boolean mLeftEdge;
- private boolean mTopEdge;
- private Key mRightEdgeKey = null;
- private final KeyStyles mKeyStyles = new KeyStyles();
-
- /**
- * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
- * Some of the key size defaults can be overridden per row from what the {@link Keyboard}
- * defines.
- */
- public static class Row {
- // keyWidth enum constants
- private static final int KEYWIDTH_NOT_ENUM = 0;
- private static final int KEYWIDTH_FILL_RIGHT = -1;
- private static final int KEYWIDTH_FILL_BOTH = -2;
-
- private final KeyboardParams mParams;
- /** Default width of a key in this row. */
- public final float mDefaultKeyWidth;
- /** Default height of a key in this row. */
- public final int mRowHeight;
-
- private final int mCurrentY;
- // Will be updated by {@link Key}'s constructor.
- private float mCurrentX;
-
- public Row(Resources res, KeyboardParams params, XmlPullParser parser, int y) {
- mParams = params;
- TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard);
- mRowHeight = (int)KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_rowHeight, params.mBaseHeight, params.mDefaultRowHeight);
- keyboardAttr.recycle();
- TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Key);
- mDefaultKeyWidth = KeyboardBuilder.getDimensionOrFraction(keyAttr,
- R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, params.mDefaultKeyWidth);
- keyAttr.recycle();
-
- mCurrentY = y;
- mCurrentX = 0.0f;
- }
-
- public void setXPos(float keyXPos) {
- mCurrentX = keyXPos;
- }
-
- public void advanceXPos(float width) {
- mCurrentX += width;
- }
-
- public int getKeyY() {
- return mCurrentY;
- }
-
- public float getKeyX(TypedArray keyAttr) {
- final int widthType = KeyboardBuilder.getEnumValue(keyAttr,
- R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
- if (widthType == KEYWIDTH_FILL_BOTH) {
- // If keyWidth is fillBoth, the key width should start right after the nearest key
- // on the left hand side.
- return mCurrentX;
- }
-
- final int keyboardRightEdge = mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding;
- if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
- final float keyXPos = KeyboardBuilder.getDimensionOrFraction(keyAttr,
- R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0);
- if (keyXPos < 0) {
- // If keyXPos is negative, the actual x-coordinate will be
- // keyboardWidth + keyXPos.
- // keyXPos shouldn't be less than mCurrentX because drawable area for this key
- // starts at mCurrentX. Or, this key will overlaps the adjacent key on its left
- // hand side.
- return Math.max(keyXPos + keyboardRightEdge, mCurrentX);
- } else {
- return keyXPos + mParams.mHorizontalEdgesPadding;
- }
- }
- return mCurrentX;
- }
-
- public float getKeyWidth(TypedArray keyAttr, float keyXPos) {
- final int widthType = KeyboardBuilder.getEnumValue(keyAttr,
- R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
- switch (widthType) {
- case KEYWIDTH_FILL_RIGHT:
- case KEYWIDTH_FILL_BOTH:
- final int keyboardRightEdge =
- mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding;
- // If keyWidth is fillRight, the actual key width will be determined to fill out the
- // area up to the right edge of the keyboard.
- // If keyWidth is fillBoth, the actual key width will be determined to fill out the
- // area between the nearest key on the left hand side and the right edge of the
- // keyboard.
- return keyboardRightEdge - keyXPos;
- default: // KEYWIDTH_NOT_ENUM
- return KeyboardBuilder.getDimensionOrFraction(keyAttr,
- R.styleable.Keyboard_Key_keyWidth, mParams.mBaseWidth, mDefaultKeyWidth);
- }
- }
- }
-
- public KeyboardBuilder(Context context, KP params) {
- mContext = context;
- final Resources res = context.getResources();
- mResources = res;
- mDisplayMetrics = res.getDisplayMetrics();
-
- mParams = params;
-
- setTouchPositionCorrectionData(context, params);
-
- params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
- params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
- }
-
- private static void setTouchPositionCorrectionData(Context context, KeyboardParams params) {
- final TypedArray a = context.obtainStyledAttributes(
- null, R.styleable.Keyboard, R.attr.keyboardStyle, 0);
- params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0);
- final int resourceId = a.getResourceId(R.styleable.Keyboard_touchPositionCorrectionData, 0);
- a.recycle();
- if (resourceId == 0) {
- if (LatinImeLogger.sDBG)
- throw new RuntimeException("touchPositionCorrectionData is not defined");
- return;
- }
-
- final String[] data = context.getResources().getStringArray(resourceId);
- params.mTouchPositionCorrection.load(data);
- }
-
- public KeyboardBuilder<KP> load(KeyboardId id) {
- mParams.mId = id;
- final XmlResourceParser parser = mResources.getXml(id.getXmlId());
- try {
- parseKeyboard(parser);
- } catch (XmlPullParserException e) {
- Log.w(TAG, "keyboard XML parse error: " + e);
- throw new IllegalArgumentException(e);
- } catch (IOException e) {
- Log.w(TAG, "keyboard XML parse error: " + e);
- throw new RuntimeException(e);
- } finally {
- parser.close();
- }
- return this;
- }
-
- public void setTouchPositionCorrectionEnabled(boolean enabled) {
- mParams.mTouchPositionCorrection.setEnabled(enabled);
- }
-
- public Keyboard build() {
- return new Keyboard(mParams);
- }
-
- private void parseKeyboard(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mParams.mId));
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_KEYBOARD.equals(tag)) {
- parseKeyboardAttributes(parser);
- startKeyboard();
- parseKeyboardContent(parser, false);
- break;
- } else {
- throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD);
- }
- }
- }
- }
-
- private void parseKeyboardAttributes(XmlPullParser parser) {
- final int displayWidth = mDisplayMetrics.widthPixels;
- final TypedArray keyboardAttr = mContext.obtainStyledAttributes(
- Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle,
- R.style.Keyboard);
- final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Key);
- try {
- final int displayHeight = mDisplayMetrics.heightPixels;
- final int keyboardHeight = (int)keyboardAttr.getDimension(
- R.styleable.Keyboard_keyboardHeight, displayHeight / 2);
- final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2);
- int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2);
- if (minKeyboardHeight < 0) {
- // Specified fraction was negative, so it should be calculated against display
- // width.
- minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2);
- }
- final KeyboardParams params = mParams;
- // Keyboard height will not exceed maxKeyboardHeight and will not be less than
- // minKeyboardHeight.
- params.mOccupiedHeight = Math.max(
- Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
- params.mOccupiedWidth = params.mId.mWidth;
- params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0);
- params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0);
- params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_keyboardHorizontalEdgesPadding, mParams.mOccupiedWidth, 0);
-
- params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2
- - params.mHorizontalCenterPadding;
- params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr,
- R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth,
- params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS);
- params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0);
- params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0);
- params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding
- - params.mBottomPadding + params.mVerticalGap;
- params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_rowHeight, params.mBaseHeight,
- params.mBaseHeight / DEFAULT_KEYBOARD_ROWS);
-
- params.mIsRtlKeyboard = keyboardAttr.getBoolean(
- R.styleable.Keyboard_isRtlKeyboard, false);
- params.mMoreKeysTemplate = keyboardAttr.getResourceId(
- R.styleable.Keyboard_moreKeysTemplate, 0);
- params.mMaxMiniKeyboardColumn = keyAttr.getInt(
- R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);
-
- params.mIconsSet.loadIcons(keyboardAttr);
- } finally {
- keyAttr.recycle();
- keyboardAttr.recycle();
- }
- }
-
- private void parseKeyboardContent(XmlPullParser parser, boolean skip)
- throws XmlPullParserException, IOException {
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_ROW.equals(tag)) {
- Row row = parseRowAttributes(parser);
- if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW));
- if (!skip)
- startRow(row);
- parseRowContent(parser, row, skip);
- } else if (TAG_INCLUDE.equals(tag)) {
- parseIncludeKeyboardContent(parser, skip);
- } else if (TAG_SWITCH.equals(tag)) {
- parseSwitchKeyboardContent(parser, skip);
- } else if (TAG_KEY_STYLE.equals(tag)) {
- parseKeyStyle(parser, skip);
- } else {
- throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW);
- }
- } else if (event == XmlPullParser.END_TAG) {
- final String tag = parser.getName();
- if (TAG_KEYBOARD.equals(tag)) {
- endKeyboard();
- break;
- } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)
- || TAG_MERGE.equals(tag)) {
- if (DEBUG) Log.d(TAG, String.format("</%s>", tag));
- break;
- } else if (TAG_KEY_STYLE.equals(tag)) {
- continue;
- } else {
- throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW);
- }
- }
- }
- }
-
- private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException {
- final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard);
- try {
- if (a.hasValue(R.styleable.Keyboard_horizontalGap))
- throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap");
- if (a.hasValue(R.styleable.Keyboard_verticalGap))
- throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap");
- return new Row(mResources, mParams, parser, mCurrentY);
- } finally {
- a.recycle();
- }
- }
-
- private void parseRowContent(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_KEY.equals(tag)) {
- parseKey(parser, row, skip);
- } else if (TAG_SPACER.equals(tag)) {
- parseSpacer(parser, row, skip);
- } else if (TAG_INCLUDE.equals(tag)) {
- parseIncludeRowContent(parser, row, skip);
- } else if (TAG_SWITCH.equals(tag)) {
- parseSwitchRowContent(parser, row, skip);
- } else if (TAG_KEY_STYLE.equals(tag)) {
- parseKeyStyle(parser, skip);
- } else {
- throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
- }
- } else if (event == XmlPullParser.END_TAG) {
- final String tag = parser.getName();
- if (TAG_ROW.equals(tag)) {
- if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_ROW));
- if (!skip)
- endRow(row);
- break;
- } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)
- || TAG_MERGE.equals(tag)) {
- if (DEBUG) Log.d(TAG, String.format("</%s>", tag));
- break;
- } else if (TAG_KEY_STYLE.equals(tag)) {
- continue;
- } else {
- throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
- }
- }
- }
- }
-
- private void parseKey(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- if (skip) {
- XmlParseUtils.checkEndTag(TAG_KEY, parser);
- } else {
- final Key key = new Key(mResources, mParams, row, parser, mKeyStyles);
- if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />",
- TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode,
- Arrays.toString(key.mMoreKeys)));
- XmlParseUtils.checkEndTag(TAG_KEY, parser);
- endKey(key);
- }
- }
-
- private void parseSpacer(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- if (skip) {
- XmlParseUtils.checkEndTag(TAG_SPACER, parser);
- } else {
- final Key.Spacer spacer = new Key.Spacer(mResources, mParams, row, parser, mKeyStyles);
- if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER));
- XmlParseUtils.checkEndTag(TAG_SPACER, parser);
- endKey(spacer);
- }
- }
-
- private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip)
- throws XmlPullParserException, IOException {
- parseIncludeInternal(parser, null, skip);
- }
-
- private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- parseIncludeInternal(parser, row, skip);
- }
-
- private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- if (skip) {
- XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
- } else {
- final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Include);
- int keyboardLayout = 0;
- try {
- XmlParseUtils.checkAttributeExists(a,
- R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout",
- TAG_INCLUDE, parser);
- keyboardLayout = a.getResourceId(R.styleable.Keyboard_Include_keyboardLayout, 0);
- } finally {
- a.recycle();
- }
-
- XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
- if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />",
- TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout)));
- final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout);
- try {
- parseMerge(parserForInclude, row, skip);
- } finally {
- parserForInclude.close();
- }
- }
- }
-
- private void parseMerge(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_MERGE.equals(tag)) {
- if (row == null) {
- parseKeyboardContent(parser, skip);
- } else {
- parseRowContent(parser, row, skip);
- }
- break;
- } else {
- throw new XmlParseUtils.ParseException(
- "Included keyboard layout must have <merge> root element", parser);
- }
- }
- }
- }
-
- private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip)
- throws XmlPullParserException, IOException {
- parseSwitchInternal(parser, null, skip);
- }
-
- private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- parseSwitchInternal(parser, row, skip);
- }
-
- private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mParams.mId));
- boolean selected = false;
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_CASE.equals(tag)) {
- selected |= parseCase(parser, row, selected ? true : skip);
- } else if (TAG_DEFAULT.equals(tag)) {
- selected |= parseDefault(parser, row, selected ? true : skip);
- } else {
- throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
- }
- } else if (event == XmlPullParser.END_TAG) {
- final String tag = parser.getName();
- if (TAG_SWITCH.equals(tag)) {
- if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_SWITCH));
- break;
- } else {
- throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
- }
- }
- }
- }
-
- private boolean parseCase(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- final boolean selected = parseCaseCondition(parser);
- if (row == null) {
- // Processing Rows.
- parseKeyboardContent(parser, selected ? skip : true);
- } else {
- // Processing Keys.
- parseRowContent(parser, row, selected ? skip : true);
- }
- return selected;
- }
-
- private boolean parseCaseCondition(XmlPullParser parser) {
- final KeyboardId id = mParams.mId;
- if (id == null)
- return true;
-
- final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Case);
- try {
- final boolean modeMatched = matchTypedValue(a,
- R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode));
- final boolean navigateActionMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_navigateAction, id.navigateAction());
- final boolean passwordInputMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_passwordInput, id.passwordInput());
- final boolean hasSettingsKeyMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_hasSettingsKey, id.hasSettingsKey());
- final boolean f2KeyModeMatched = matchInteger(a,
- R.styleable.Keyboard_Case_f2KeyMode, id.f2KeyMode());
- final boolean clobberSettingsKeyMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey);
- final boolean shortcutKeyEnabledMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled);
- final boolean hasShortcutKeyMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey);
- // As noted at {@link KeyboardId} class, we are interested only in enum value masked by
- // {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and
- // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching
- // this attribute with id.mImeOptions as integer value is enough for our purpose.
- final boolean imeActionMatched = matchInteger(a,
- R.styleable.Keyboard_Case_imeAction, id.imeAction());
- final boolean localeCodeMatched = matchString(a,
- R.styleable.Keyboard_Case_localeCode, id.mLocale.toString());
- final boolean languageCodeMatched = matchString(a,
- R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
- final boolean countryCodeMatched = matchString(a,
- R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
- final boolean selected = modeMatched && navigateActionMatched && passwordInputMatched
- && hasSettingsKeyMatched && f2KeyModeMatched && clobberSettingsKeyMatched
- && shortcutKeyEnabledMatched && hasShortcutKeyMatched && imeActionMatched &&
- localeCodeMatched && languageCodeMatched && countryCodeMatched;
-
- if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
- textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"),
- booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"),
- booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
- booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"),
- textAttr(KeyboardId.f2KeyModeName(
- a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), "f2KeyMode"),
- booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey,
- "clobberSettingsKey"),
- booleanAttr(
- a, R.styleable.Keyboard_Case_shortcutKeyEnabled, "shortcutKeyEnabled"),
- booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"),
- textAttr(EditorInfoCompatUtils.imeOptionsName(
- a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"),
- textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), "localeCode"),
- textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), "languageCode"),
- textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"),
- Boolean.toString(selected)));
-
- return selected;
- } finally {
- a.recycle();
- }
- }
-
- private static boolean matchInteger(TypedArray a, int index, int value) {
- // If <case> does not have "index" attribute, that means this <case> is wild-card for the
- // attribute.
- return !a.hasValue(index) || a.getInt(index, 0) == value;
- }
-
- private static boolean matchBoolean(TypedArray a, int index, boolean value) {
- // If <case> does not have "index" attribute, that means this <case> is wild-card for the
- // attribute.
- return !a.hasValue(index) || a.getBoolean(index, false) == value;
- }
-
- private static boolean matchString(TypedArray a, int index, String value) {
- // If <case> does not have "index" attribute, that means this <case> is wild-card for the
- // attribute.
- return !a.hasValue(index) || stringArrayContains(a.getString(index).split("\\|"), value);
- }
-
- private static boolean matchTypedValue(TypedArray a, int index, int intValue, String strValue) {
- // If <case> does not have "index" attribute, that means this <case> is wild-card for the
- // attribute.
- final TypedValue v = a.peekValue(index);
- if (v == null)
- return true;
-
- if (isIntegerValue(v)) {
- return intValue == a.getInt(index, 0);
- } else if (isStringValue(v)) {
- return stringArrayContains(a.getString(index).split("\\|"), strValue);
- }
- return false;
- }
-
- private static boolean stringArrayContains(String[] array, String value) {
- for (final String elem : array) {
- if (elem.equals(value))
- return true;
- }
- return false;
- }
-
- private boolean parseDefault(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT));
- if (row == null) {
- parseKeyboardContent(parser, skip);
- } else {
- parseRowContent(parser, row, skip);
- }
- return true;
- }
-
- private void parseKeyStyle(XmlPullParser parser, boolean skip)
- throws XmlPullParserException {
- TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_KeyStyle);
- TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Key);
- try {
- if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName))
- throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE
- + "/> needs styleName attribute", parser);
- if (!skip)
- mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
- } finally {
- keyStyleAttr.recycle();
- keyAttrs.recycle();
- }
- }
-
- private void startKeyboard() {
- mCurrentY += mParams.mTopPadding;
- mTopEdge = true;
- }
-
- private void startRow(Row row) {
- addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
- mCurrentRow = row;
- mLeftEdge = true;
- mRightEdgeKey = null;
- }
-
- private void endRow(Row row) {
- if (mCurrentRow == null)
- throw new InflateException("orphant end row tag");
- if (mRightEdgeKey != null) {
- mRightEdgeKey.markAsRightEdge(mParams);
- mRightEdgeKey = null;
- }
- addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
- mCurrentY += row.mRowHeight;
- mCurrentRow = null;
- mTopEdge = false;
- }
-
- private void endKey(Key key) {
- mParams.onAddKey(key);
- if (mLeftEdge) {
- key.markAsLeftEdge(mParams);
- mLeftEdge = false;
- }
- if (mTopEdge) {
- key.markAsTopEdge(mParams);
- }
- mRightEdgeKey = key;
- }
-
- private void endKeyboard() {
- // nothing to do here.
- }
-
- private void addEdgeSpace(float width, Row row) {
- row.advanceXPos(width);
- mLeftEdge = false;
- mRightEdgeKey = null;
- }
-
- public static float getDimensionOrFraction(TypedArray a, int index, int base, float defValue) {
- final TypedValue value = a.peekValue(index);
- if (value == null)
- return defValue;
- if (isFractionValue(value)) {
- return a.getFraction(index, base, base, defValue);
- } else if (isDimensionValue(value)) {
- return a.getDimension(index, defValue);
- }
- return defValue;
- }
-
- public static int getEnumValue(TypedArray a, int index, int defValue) {
- final TypedValue value = a.peekValue(index);
- if (value == null)
- return defValue;
- if (isIntegerValue(value)) {
- return a.getInt(index, defValue);
- }
- return defValue;
- }
-
- private static boolean isFractionValue(TypedValue v) {
- return v.type == TypedValue.TYPE_FRACTION;
- }
-
- private static boolean isDimensionValue(TypedValue v) {
- return v.type == TypedValue.TYPE_DIMENSION;
- }
-
- private static boolean isIntegerValue(TypedValue v) {
- return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT;
- }
-
- private static boolean isStringValue(TypedValue v) {
- return v.type == TypedValue.TYPE_STRING;
- }
-
- private static String textAttr(String value, String name) {
- return value != null ? String.format(" %s=%s", name, value) : "";
- }
-
- private static String booleanAttr(TypedArray a, int index, String name) {
- return a.hasValue(index) ? String.format(" %s=%s", name, a.getBoolean(index, false)) : "";
- }
-}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
index faa5f86f2..6313a61b5 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
@@ -23,80 +23,75 @@ import android.util.Log;
import com.android.inputmethod.latin.R;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
public class KeyboardIconsSet {
private static final String TAG = KeyboardIconsSet.class.getSimpleName();
public static final int ICON_UNDEFINED = 0;
- // This should be aligned with Keyboard.keyIcon enum.
- private static final int ICON_SHIFT_KEY = 1;
- private static final int ICON_DELETE_KEY = 2;
- private static final int ICON_SETTINGS_KEY = 3; // This is also represented as "@icon/3" in XML.
- private static final int ICON_SPACE_KEY = 4;
- private static final int ICON_RETURN_KEY = 5;
- private static final int ICON_SEARCH_KEY = 6;
- private static final int ICON_TAB_KEY = 7; // This is also represented as "@icon/7" in XML.
- private static final int ICON_SHORTCUT_KEY = 8;
- private static final int ICON_SHORTCUT_FOR_LABEL = 9;
- // This should be aligned with Keyboard.keyIconShifted enum.
- private static final int ICON_SHIFTED_SHIFT_KEY = 10;
- // This should be aligned with Keyboard.keyIconPreview enum.
- private static final int ICON_PREVIEW_TAB_KEY = 11;
+ private final Map<Integer, Drawable> mIcons = new HashMap<Integer, Drawable>();
- private static final int ICON_LAST = 11;
+ // The key value should be aligned with the enum value of Keyboard.icon*.
+ private static final Map<Integer, Integer> ICONS_TO_ATTRS_MAP = new HashMap<Integer, Integer>();
+ private static final Collection<Integer> VALID_ATTRS;
- private final Drawable mIcons[] = new Drawable[ICON_LAST + 1];
+ static {
+ addIconIdMap(1, R.styleable.Keyboard_iconShiftKey);
+ addIconIdMap(2, R.styleable.Keyboard_iconDeleteKey);
+ // This is also represented as "@icon/3" in keyboard layout XML.
+ addIconIdMap(3, R.styleable.Keyboard_iconSettingsKey);
+ addIconIdMap(4, R.styleable.Keyboard_iconSpaceKey);
+ addIconIdMap(5, R.styleable.Keyboard_iconReturnKey);
+ addIconIdMap(6, R.styleable.Keyboard_iconSearchKey);
+ // This is also represented as "@icon/7" in keyboard layout XML.
+ addIconIdMap(7, R.styleable.Keyboard_iconTabKey);
+ addIconIdMap(8, R.styleable.Keyboard_iconShortcutKey);
+ addIconIdMap(9, R.styleable.Keyboard_iconShortcutForLabel);
+ addIconIdMap(10, R.styleable.Keyboard_iconSpaceKeyForNumberLayout);
+ addIconIdMap(11, R.styleable.Keyboard_iconShiftKeyShifted);
+ addIconIdMap(12, R.styleable.Keyboard_iconDisabledShortcutKey);
+ addIconIdMap(13, R.styleable.Keyboard_iconPreviewTabKey);
+ VALID_ATTRS = ICONS_TO_ATTRS_MAP.values();
+ }
- private static final int getIconId(final int attrIndex) {
- switch (attrIndex) {
- case R.styleable.Keyboard_iconShiftKey:
- return ICON_SHIFT_KEY;
- case R.styleable.Keyboard_iconDeleteKey:
- return ICON_DELETE_KEY;
- case R.styleable.Keyboard_iconSettingsKey:
- return ICON_SETTINGS_KEY;
- case R.styleable.Keyboard_iconSpaceKey:
- return ICON_SPACE_KEY;
- case R.styleable.Keyboard_iconReturnKey:
- return ICON_RETURN_KEY;
- case R.styleable.Keyboard_iconSearchKey:
- return ICON_SEARCH_KEY;
- case R.styleable.Keyboard_iconTabKey:
- return ICON_TAB_KEY;
- case R.styleable.Keyboard_iconShortcutKey:
- return ICON_SHORTCUT_KEY;
- case R.styleable.Keyboard_iconShortcutForLabel:
- return ICON_SHORTCUT_FOR_LABEL;
- case R.styleable.Keyboard_iconShiftedShiftKey:
- return ICON_SHIFTED_SHIFT_KEY;
- case R.styleable.Keyboard_iconPreviewTabKey:
- return ICON_PREVIEW_TAB_KEY;
- default:
- return ICON_UNDEFINED;
- }
+ private static void addIconIdMap(int iconId, int attrId) {
+ ICONS_TO_ATTRS_MAP.put(iconId, attrId);
}
public void loadIcons(final TypedArray keyboardAttrs) {
- final int count = keyboardAttrs.getIndexCount();
- for (int i = 0; i < count; i++) {
- final int attrIndex = keyboardAttrs.getIndex(i);
- final int iconId = getIconId(attrIndex);
- if (iconId != ICON_UNDEFINED) {
- try {
- mIcons[iconId] = setDefaultBounds(keyboardAttrs.getDrawable(attrIndex));
- } catch (Resources.NotFoundException e) {
- Log.w(TAG, "Drawable resource for icon #" + iconId + " not found");
- }
+ for (final Integer attrId : VALID_ATTRS) {
+ try {
+ final Drawable icon = keyboardAttrs.getDrawable(attrId);
+ if (icon == null) continue;
+ setDefaultBounds(icon);
+ mIcons.put(attrId, icon);
+ } catch (Resources.NotFoundException e) {
+ Log.w(TAG, "Drawable resource for icon #"
+ + keyboardAttrs.getResources().getResourceEntryName(attrId)
+ + " not found");
}
}
}
- public Drawable getIcon(final int iconId) {
- if (iconId == ICON_UNDEFINED)
+ public Drawable getIconByIconId(final Integer iconId) {
+ if (iconId == ICON_UNDEFINED) {
return null;
- if (iconId < 0 || iconId >= mIcons.length)
+ }
+ final Integer attrId = ICONS_TO_ATTRS_MAP.get(iconId);
+ if (attrId == null) {
throw new IllegalArgumentException("icon id is out of range: " + iconId);
- return mIcons[iconId];
+ }
+ return getIconByAttrId(attrId);
+ }
+
+ public Drawable getIconByAttrId(final Integer attrId) {
+ if (!VALID_ATTRS.contains(attrId)) {
+ throw new IllegalArgumentException("unknown icon attribute id: " + attrId);
+ }
+ return mIcons.get(attrId);
}
private static Drawable setDefaultBounds(final Drawable icon) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
deleted file mode 100644
index 64cd37c4b..000000000
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.keyboard.internal;
-
-import android.graphics.drawable.Drawable;
-
-import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardId;
-import com.android.inputmethod.latin.LatinImeLogger;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public class KeyboardParams {
- public KeyboardId mId;
- public int mThemeId;
-
- /** Total height and width of the keyboard, including the paddings and keys */
- public int mOccupiedHeight;
- public int mOccupiedWidth;
-
- /** Base height and width of the keyboard used to calculate rows' or keys' heights and widths */
- public int mBaseHeight;
- public int mBaseWidth;
-
- public int mTopPadding;
- public int mBottomPadding;
- public int mHorizontalEdgesPadding;
- public int mHorizontalCenterPadding;
-
- public int mDefaultRowHeight;
- public int mDefaultKeyWidth;
- public int mHorizontalGap;
- public int mVerticalGap;
-
- public boolean mIsRtlKeyboard;
- public int mMoreKeysTemplate;
- public int mMaxMiniKeyboardColumn;
-
- public int GRID_WIDTH;
- public int GRID_HEIGHT;
-
- public final List<Key> mKeys = new ArrayList<Key>();
- public final List<Key> mShiftKeys = new ArrayList<Key>();
- public final Set<Key> mShiftLockKeys = new HashSet<Key>();
- public final Map<Key, Drawable> mShiftedIcons = new HashMap<Key, Drawable>();
- public final Map<Key, Drawable> mUnshiftedIcons = new HashMap<Key, Drawable>();
- public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
-
- public int mMostCommonKeyHeight = 0;
- public int mMostCommonKeyWidth = 0;
-
- public final TouchPositionCorrection mTouchPositionCorrection = new TouchPositionCorrection();
-
- public static class TouchPositionCorrection {
- private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3;
-
- public boolean mEnabled;
- public float[] mXs;
- public float[] mYs;
- public float[] mRadii;
-
- public void load(String[] data) {
- final int dataLength = data.length;
- if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
- if (LatinImeLogger.sDBG)
- throw new RuntimeException(
- "the size of touch position correction data is invalid");
- return;
- }
-
- final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
- mXs = new float[length];
- mYs = new float[length];
- mRadii = new float[length];
- try {
- for (int i = 0; i < dataLength; ++i) {
- final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE;
- final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
- final float value = Float.parseFloat(data[i]);
- if (type == 0) {
- mXs[index] = value;
- } else if (type == 1) {
- mYs[index] = value;
- } else {
- mRadii[index] = value;
- }
- }
- } catch (NumberFormatException e) {
- if (LatinImeLogger.sDBG) {
- throw new RuntimeException(
- "the number format for touch position correction data is invalid");
- }
- mXs = null;
- mYs = null;
- mRadii = null;
- }
- }
-
- public void setEnabled(boolean enabled) {
- mEnabled = enabled;
- }
-
- public boolean isValid() {
- return mEnabled && mXs != null && mYs != null && mRadii != null
- && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
- }
- }
-
- protected void clearKeys() {
- mKeys.clear();
- mShiftKeys.clear();
- mShiftLockKeys.clear();
- mShiftedIcons.clear();
- mUnshiftedIcons.clear();
- clearHistogram();
- }
-
- public void onAddKey(Key key) {
- mKeys.add(key);
- updateHistogram(key);
- if (key.mCode == Keyboard.CODE_SHIFT) {
- mShiftKeys.add(key);
- if (key.isSticky()) {
- mShiftLockKeys.add(key);
- }
- }
- }
-
- public void addShiftedIcon(Key key, Drawable icon) {
- mUnshiftedIcons.put(key, key.getIcon());
- mShiftedIcons.put(key, icon);
- }
-
- private int mMaxHeightCount = 0;
- private int mMaxWidthCount = 0;
- private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>();
- private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>();
-
- private void clearHistogram() {
- mMostCommonKeyHeight = 0;
- mMaxHeightCount = 0;
- mHeightHistogram.clear();
-
- mMaxWidthCount = 0;
- mMostCommonKeyWidth = 0;
- mWidthHistogram.clear();
- }
-
- private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) {
- final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1;
- histogram.put(key, count);
- return count;
- }
-
- private void updateHistogram(Key key) {
- final Integer height = key.mHeight + key.mVerticalGap;
- final int heightCount = updateHistogramCounter(mHeightHistogram, height);
- if (heightCount > mMaxHeightCount) {
- mMaxHeightCount = heightCount;
- mMostCommonKeyHeight = height;
- }
-
- final Integer width = key.mWidth + key.mHorizontalGap;
- final int widthCount = updateHistogramCounter(mWidthHistogram, width);
- if (widthCount > mMaxWidthCount) {
- mMaxWidthCount = widthCount;
- mMostCommonKeyWidth = width;
- }
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java
new file mode 100644
index 000000000..78b2de342
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/InputAttributes.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.text.InputType;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.inputmethod.compat.InputTypeCompatUtils;
+
+/**
+ * Class to hold attributes of the input field.
+ */
+public class InputAttributes {
+ private final String TAG = InputAttributes.class.getSimpleName();
+
+ final public boolean mInsertSpaceOnPickSuggestionManually;
+ final public boolean mInputTypeNoAutoCorrect;
+ final public boolean mIsSettingsSuggestionStripOn;
+ final public boolean mApplicationSpecifiedCompletionOn;
+
+ public InputAttributes(final EditorInfo editorInfo, final boolean isFullscreenMode) {
+ if (editorInfo == null || editorInfo.inputType == InputType.TYPE_CLASS_TEXT) {
+ mInsertSpaceOnPickSuggestionManually = false;
+ mIsSettingsSuggestionStripOn = false;
+ mInputTypeNoAutoCorrect = false;
+ mApplicationSpecifiedCompletionOn = false;
+ } else {
+ final int inputType = editorInfo.inputType;
+ if (inputType == InputType.TYPE_NULL) {
+ // TODO: We should honor TYPE_NULL specification.
+ Log.i(TAG, "InputType.TYPE_NULL is specified");
+ }
+ final int inputClass = inputType & InputType.TYPE_MASK_CLASS;
+ final int variation = inputType & InputType.TYPE_MASK_VARIATION;
+ if (inputClass == 0) {
+ // TODO: is this check still necessary?
+ Log.w(TAG, String.format("Unexpected input class: inputType=0x%08x"
+ + " imeOptions=0x%08x",
+ inputType, editorInfo.imeOptions));
+ }
+ final boolean flagNoSuggestions =
+ 0 != (inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
+ final boolean flagMultiLine =
+ 0 != (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE);
+ final boolean flagAutoCorrect =
+ 0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
+ final boolean flagAutoComplete =
+ 0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE);
+
+ // Make sure that passwords are not displayed in {@link SuggestionsView}.
+ if (InputTypeCompatUtils.isPasswordInputType(inputType)
+ || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)
+ || InputTypeCompatUtils.isEmailVariation(variation)
+ || InputType.TYPE_TEXT_VARIATION_URI == variation
+ || InputType.TYPE_TEXT_VARIATION_FILTER == variation
+ || flagNoSuggestions
+ || flagAutoComplete) {
+ mIsSettingsSuggestionStripOn = false;
+ } else {
+ mIsSettingsSuggestionStripOn = true;
+ }
+
+ if (InputTypeCompatUtils.isEmailVariation(variation)
+ || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
+ // The point in turning this off is that we don't want to insert a space after
+ // a name when filling a form: we can't delete trailing spaces when changing fields
+ mInsertSpaceOnPickSuggestionManually = false;
+ } else {
+ mInsertSpaceOnPickSuggestionManually = true;
+ }
+
+ // If it's a browser edit field and auto correct is not ON explicitly, then
+ // disable auto correction, but keep suggestions on.
+ // If NO_SUGGESTIONS is set, don't do prediction.
+ // If it's not multiline and the autoCorrect flag is not set, then don't correct
+ if ((variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
+ && !flagAutoCorrect)
+ || flagNoSuggestions
+ || (!flagAutoCorrect && !flagMultiLine)) {
+ mInputTypeNoAutoCorrect = true;
+ } else {
+ mInputTypeNoAutoCorrect = false;
+ }
+
+ mApplicationSpecifiedCompletionOn = flagAutoComplete && isFullscreenMode;
+ }
+ }
+
+ // Pretty print
+ @Override
+ public String toString() {
+ return "\n mInsertSpaceOnPickSuggestionManually = " + mInsertSpaceOnPickSuggestionManually
+ + "\n mInputTypeNoAutoCorrect = " + mInputTypeNoAutoCorrect
+ + "\n mIsSettingsSuggestionStripOn = " + mIsSettingsSuggestionStripOn
+ + "\n mApplicationSpecifiedCompletionOn = " + mApplicationSpecifiedCompletionOn;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index a0c59671f..60f8ce8d8 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -65,8 +65,8 @@ import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
-import com.android.inputmethod.keyboard.LatinKeyboard;
import com.android.inputmethod.keyboard.LatinKeyboardView;
+import com.android.inputmethod.latin.suggestions.SuggestionsView;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -175,6 +175,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private int mSpaceState;
private SettingsValues mSettingsValues;
+ private InputAttributes mInputAttributes;
private View mExtractArea;
private View mKeyPreviewBackingView;
@@ -195,18 +196,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private UserUnigramDictionary mUserUnigramDictionary;
private boolean mIsUserDictionaryAvailable;
- // TODO: Create an inner class to group options and pseudo-options to improve readability.
- // These variables are initialized according to the {@link EditorInfo#inputType}.
- private boolean mInsertSpaceOnPickSuggestionManually;
- private boolean mInputTypeNoAutoCorrect;
- private boolean mIsSettingsSuggestionStripOn;
- private boolean mApplicationSpecifiedCompletionOn;
-
private WordComposer mWordComposer = new WordComposer();
- private boolean mHasUncommittedTypedChars;
private int mCorrectionMode;
- private String mWordSavedForAutoCorrectCancellation;
// Keep track of the last selection range to decide if we need to show word alternatives
private int mLastSelectionStart;
private int mLastSelectionEnd;
@@ -299,13 +291,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
setSpacebarTextFadeFactor(inputView,
(1.0f + mFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
- (LatinKeyboard)msg.obj);
+ (Keyboard)msg.obj);
sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
mDurationOfFadeoutLanguageOnSpacebar);
break;
case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
setSpacebarTextFadeFactor(inputView, mFinalFadeoutFactorOfLanguageOnSpacebar,
- (LatinKeyboard)msg.obj);
+ (Keyboard)msg.obj);
break;
}
}
@@ -346,15 +338,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
private static void setSpacebarTextFadeFactor(LatinKeyboardView inputView,
- float fadeFactor, LatinKeyboard oldKeyboard) {
+ float fadeFactor, Keyboard oldKeyboard) {
if (inputView == null) return;
final Keyboard keyboard = inputView.getKeyboard();
- if (keyboard instanceof LatinKeyboard && keyboard == oldKeyboard) {
- final Key updatedKey = ((LatinKeyboard)keyboard).updateSpacebarLanguage(
- fadeFactor,
- Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */),
- SubtypeSwitcher.getInstance().needsToDisplayLanguage(keyboard.mId.mLocale));
- inputView.invalidateKey(updatedKey);
+ if (keyboard == oldKeyboard) {
+ inputView.updateSpacebar(fadeFactor,
+ SubtypeSwitcher.getInstance().needsToDisplayLanguage(
+ keyboard.mId.mLocale));
}
}
@@ -364,7 +354,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView();
if (inputView != null) {
- final LatinKeyboard keyboard = latinIme.mKeyboardSwitcher.getLatinKeyboard();
+ final Keyboard keyboard = latinIme.mKeyboardSwitcher.getKeyboard();
// The language is always displayed when the delay is negative.
final boolean needsToDisplayLanguage = localeChanged
|| mDelayBeforeFadeoutLanguageOnSpacebar < 0;
@@ -498,7 +488,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
InputMethodManagerCompatWrapper.init(this);
SubtypeSwitcher.init(this);
KeyboardSwitcher.init(this, prefs);
- AccessibilityUtils.init(this, prefs);
+ AccessibilityUtils.init(this);
super.onCreate();
@@ -514,6 +504,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
loadSettings();
+ // TODO: remove the following when it's not needed by updateCorrectionMode() any more
+ mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */);
Utils.GCUtils.getInstance().reset();
boolean tryGC = true;
for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
@@ -756,18 +748,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// The EditorInfo might have a flag that affects fullscreen mode.
// Note: This call should be done by InputMethodService?
updateFullscreenMode();
- initializeInputAttributes(editorInfo);
+ mInputAttributes = new InputAttributes(editorInfo, isFullscreenMode());
+ mApplicationSpecifiedCompletions = null;
inputView.closing();
mEnteredText = null;
mWordComposer.reset();
- mHasUncommittedTypedChars = false;
mDeleteCount = 0;
mSpaceState = SPACE_STATE_NONE;
loadSettings();
updateCorrectionMode();
- updateSuggestionVisibility(mPrefs, mResources);
+ updateSuggestionVisibility(mResources);
if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) {
mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
@@ -797,73 +789,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
}
- private void initializeInputAttributes(EditorInfo editorInfo) {
- if (editorInfo == null)
- return;
- final int inputType = editorInfo.inputType;
- if (inputType == InputType.TYPE_NULL) {
- // TODO: We should honor TYPE_NULL specification.
- Log.i(TAG, "InputType.TYPE_NULL is specified");
- }
- final int inputClass = inputType & InputType.TYPE_MASK_CLASS;
- final int variation = inputType & InputType.TYPE_MASK_VARIATION;
- if (inputClass == 0) {
- Log.w(TAG, String.format("Unexpected input class: inputType=0x%08x imeOptions=0x%08x",
- inputType, editorInfo.imeOptions));
- }
-
- mInsertSpaceOnPickSuggestionManually = false;
- mInputTypeNoAutoCorrect = false;
- mIsSettingsSuggestionStripOn = false;
- mApplicationSpecifiedCompletionOn = false;
- mApplicationSpecifiedCompletions = null;
-
- if (inputClass == InputType.TYPE_CLASS_TEXT) {
- mIsSettingsSuggestionStripOn = true;
- // Make sure that passwords are not displayed in {@link SuggestionsView}.
- if (InputTypeCompatUtils.isPasswordInputType(inputType)
- || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) {
- mIsSettingsSuggestionStripOn = false;
- }
- if (InputTypeCompatUtils.isEmailVariation(variation)
- || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
- // The point in turning this off is that we don't want to insert a space after
- // a name when filling a form: we can't delete trailing spaces when changing fields
- mInsertSpaceOnPickSuggestionManually = false;
- } else {
- mInsertSpaceOnPickSuggestionManually = true;
- }
- if (InputTypeCompatUtils.isEmailVariation(variation)) {
- mIsSettingsSuggestionStripOn = false;
- } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
- mIsSettingsSuggestionStripOn = false;
- } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
- mIsSettingsSuggestionStripOn = false;
- } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
- // If it's a browser edit field and auto correct is not ON explicitly, then
- // disable auto correction, but keep suggestions on.
- if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
- mInputTypeNoAutoCorrect = true;
- }
- }
-
- // If NO_SUGGESTIONS is set, don't do prediction.
- if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
- mIsSettingsSuggestionStripOn = false;
- mInputTypeNoAutoCorrect = true;
- }
- // If it's not multiline and the autoCorrect flag is not set, then don't correct
- if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
- && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
- mInputTypeNoAutoCorrect = true;
- }
- if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
- mIsSettingsSuggestionStripOn = false;
- mApplicationSpecifiedCompletionOn = isFullscreenMode();
- }
- }
- }
-
@Override
public void onWindowHidden() {
super.onWindowHidden();
@@ -932,11 +857,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// newly inserted punctuation.
mSpaceState = SPACE_STATE_NONE;
}
- if (((mWordComposer.size() > 0 && mHasUncommittedTypedChars)
+ if (((mWordComposer.isComposingWord())
|| mVoiceProxy.isVoiceInputHighlighted())
&& (selectionChanged || candidatesCleared)) {
mWordComposer.reset();
- mHasUncommittedTypedChars = false;
updateSuggestions();
final InputConnection ic = getCurrentInputConnection();
if (ic != null) {
@@ -944,7 +868,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
mComposingStateManager.onFinishComposingText();
mVoiceProxy.setVoiceInputHighlighted(false);
- } else if (!mHasUncommittedTypedChars) {
+ } else if (!mWordComposer.isComposingWord()) {
updateSuggestions();
}
}
@@ -1015,7 +939,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
}
- if (mApplicationSpecifiedCompletionOn) {
+ if (mInputAttributes.mApplicationSpecifiedCompletionOn) {
mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
if (applicationSpecifiedCompletions == null) {
clearSuggestions();
@@ -1145,9 +1069,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
public void commitTyped(final InputConnection ic) {
- if (!mHasUncommittedTypedChars) return;
- mHasUncommittedTypedChars = false;
+ if (!mWordComposer.isComposingWord()) return;
final CharSequence typedWord = mWordComposer.getTypedWord();
+ mWordComposer.onCommitWord();
if (typedWord.length() > 0) {
if (ic != null) {
ic.commitText(typedWord, 1);
@@ -1383,8 +1307,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mKeyboardSwitcher.updateShiftState();
mKeyboardSwitcher.onCodeInput(Keyboard.CODE_DUMMY);
mSpaceState = SPACE_STATE_NONE;
- mWordSavedForAutoCorrectCancellation = null;
mEnteredText = text;
+ mWordComposer.reset();
}
@Override
@@ -1420,31 +1344,28 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
return;
}
- if (mHasUncommittedTypedChars) {
+ if (mWordComposer.isComposingWord()) {
final int length = mWordComposer.size();
if (length > 0) {
mWordComposer.deleteLast();
ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
- if (mWordComposer.size() == 0) {
- mHasUncommittedTypedChars = false;
- // Remaining size equals zero means we just erased the last character of the
- // word, so we can show bigrams.
+ // If we have deleted the last remaining character of a word, then we are not
+ // isComposingWord() any more.
+ if (!mWordComposer.isComposingWord()) {
+ // Not composing word any more, so we can show bigrams.
mHandler.postUpdateBigramPredictions();
} else {
- // length > 1, so we still have letters to deduce a suggestion from.
+ // Still composing a word, so we still have letters to deduce a suggestion from.
mHandler.postUpdateSuggestions();
}
} else {
ic.deleteSurroundingText(1, 0);
}
} else {
- if (null != mWordSavedForAutoCorrectCancellation) {
+ if (mWordComposer.didAutoCorrectToAnotherWord()) {
Utils.Stats.onAutoCorrectionCancellation();
cancelAutoCorrect(ic);
- mWordSavedForAutoCorrectCancellation = null;
return;
- } else {
- mWordSavedForAutoCorrectCancellation = null;
}
if (SPACE_STATE_DOUBLE == spaceState) {
@@ -1520,7 +1441,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
if (null != ic) removeTrailingSpaceWhileInBatchEdit(ic);
}
- boolean isComposingWord = mHasUncommittedTypedChars;
+ boolean isComposingWord = mWordComposer.isComposingWord();
int code = primaryCode;
if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code))
&& isSuggestionsRequested() && !isCursorTouchingWord()) {
@@ -1557,7 +1478,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
if (isComposingWord) {
- mHasUncommittedTypedChars = true;
mWordComposer.add(code, keyCodes, x, y);
if (ic != null) {
// If it's the first letter, make note of auto-caps state
@@ -1600,16 +1520,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
if (ic != null) {
ic.beginBatchEdit();
}
- // Reset the saved word in all cases. If this separator causes an autocorrection,
- // it will overwrite this null with the actual word we need to save.
- mWordSavedForAutoCorrectCancellation = null;
- if (mHasUncommittedTypedChars) {
+ if (mWordComposer.isComposingWord()) {
// In certain languages where single quote is a separator, it's better
// not to auto correct, but accept the typed word. For instance,
// in Italian dov' should not be expanded to dove' because the elision
// requires the last vowel to be removed.
final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
- && !mInputTypeNoAutoCorrect;
+ && !mInputAttributes.mInputTypeNoAutoCorrect;
if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
commitCurrentAutoCorrection(primaryCode, ic);
} else {
@@ -1686,7 +1603,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
public boolean isSuggestionsRequested() {
- return mIsSettingsSuggestionStripOn
+ return mInputAttributes.mIsSettingsSuggestionStripOn
&& (mCorrectionMode > 0 || isShowingSuggestionsStrip());
}
@@ -1708,7 +1625,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
return true;
if (!isShowingSuggestionsStrip())
return false;
- if (mApplicationSpecifiedCompletionOn)
+ if (mInputAttributes.mApplicationSpecifiedCompletionOn)
return true;
return isSuggestionsRequested();
}
@@ -1778,7 +1695,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mHandler.cancelUpdateSuggestions();
mHandler.cancelUpdateBigramPredictions();
- if (!mHasUncommittedTypedChars) {
+ if (!mWordComposer.isComposingWord()) {
setPunctuationSuggestions();
return;
}
@@ -1793,9 +1710,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
// getSuggestedWordBuilder handles gracefully a null value of prevWord
final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(mWordComposer,
- prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo(), mCorrectionMode);
+ prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode);
- boolean autoCorrectionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
+ boolean autoCorrectionAvailable = !mInputAttributes.mInputTypeNoAutoCorrect
+ && mSuggest.hasAutoCorrection();
final CharSequence typedWord = mWordComposer.getTypedWord();
// Here, we want to promote a whitelisted word if exists.
// TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid"
@@ -1885,9 +1803,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint);
mExpectingUpdateSelection = true;
commitBestWord(autoCorrection);
- if (!autoCorrection.equals(typedWord)) {
- mWordSavedForAutoCorrectCancellation = autoCorrection.toString();
- }
// Add the word to the user unigram dictionary if it's not a known word
addToUserUnigramAndBigramDictionaries(autoCorrection,
UserUnigramDictionary.FREQUENCY_FOR_TYPED);
@@ -1911,7 +1826,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
if (ic != null) {
ic.beginBatchEdit();
}
- if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
+ if (mInputAttributes.mApplicationSpecifiedCompletionOn
+ && mApplicationSpecifiedCompletions != null
&& index >= 0 && index < mApplicationSpecifiedCompletions.length) {
if (ic != null) {
final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
@@ -1940,7 +1856,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// pressed space on purpose of displaying the suggestion strip punctuation.
final int rawPrimaryCode = suggestion.charAt(0);
// Maybe apply the "bidi mirrored" conversions for parentheses
- final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
+ final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
final boolean isRtl = keyboard != null && keyboard.mIsRtlKeyboard;
final int primaryCode = Key.getRtlParenthesisCode(rawPrimaryCode, isRtl);
@@ -1951,11 +1867,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
return;
}
- if (!mHasUncommittedTypedChars) {
- // If we are not composing a word, then it was a suggestion inferred from
- // context - no user input. We should reset the word composer.
- mWordComposer.reset();
- }
mExpectingUpdateSelection = true;
commitBestWord(suggestion);
// Add the word to the auto dictionary if it's not a known word
@@ -1965,12 +1876,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
} else {
addToOnlyBigramDictionary(suggestion, 1);
}
- // TODO: the following is fishy, because if !mHasUncommittedTypedChars we are
- // going to log an empty string
+ // TODO: the following is fishy, because it seems there may be cases where we are not
+ // composing a word at all. Maybe throw an exception if !mWordComposer.isComposingWord() ?
LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(),
suggestion.toString(), index, suggestions.mWords);
// Follow it with a space
- if (mInsertSpaceOnPickSuggestionManually) {
+ if (mInputAttributes.mInsertSpaceOnPickSuggestionManually) {
sendMagicSpace();
}
@@ -2031,7 +1942,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
ic.commitText(bestWord, 1);
}
}
- mHasUncommittedTypedChars = false;
+ mWordComposer.onCommitWord();
}
private static final WordComposer sEmptyWordComposer = new WordComposer();
@@ -2047,7 +1958,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
mSettingsValues.mWordSeparators);
SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(sEmptyWordComposer,
- prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo(), mCorrectionMode);
+ prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode);
if (builder.size() > 0) {
// Explicitly supply an empty typed word (the no-second-arg version of
@@ -2173,8 +2084,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// "ic" must not be null
private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic,
final CharSequence word) {
- mWordComposer.setComposingWord(word, mKeyboardSwitcher.getLatinKeyboard());
- mHasUncommittedTypedChars = true;
+ mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard());
mComposingStateManager.onStartComposingText();
ic.deleteSurroundingText(word.length(), 0);
ic.setComposingText(word, 1);
@@ -2183,28 +2093,32 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// "ic" must not be null
private void cancelAutoCorrect(final InputConnection ic) {
- final int cancelLength = mWordSavedForAutoCorrectCancellation.length();
+ mWordComposer.resumeSuggestionOnKeptWord();
+ final String originallyTypedWord = mWordComposer.getTypedWord();
+ final CharSequence autoCorrectedTo = mWordComposer.getAutoCorrectionOrNull();
+ final int cancelLength = autoCorrectedTo.length();
final CharSequence separator = ic.getTextBeforeCursor(1, 0);
if (DEBUG) {
final String wordBeforeCursor =
ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength)
.toString();
- if (!mWordSavedForAutoCorrectCancellation.equals(wordBeforeCursor)) {
+ if (!autoCorrectedTo.equals(wordBeforeCursor)) {
throw new RuntimeException("cancelAutoCorrect check failed: we thought we were "
- + "reverting \"" + mWordSavedForAutoCorrectCancellation
+ + "reverting \"" + autoCorrectedTo
+ "\", but before the cursor we found \"" + wordBeforeCursor + "\"");
}
- if (mWordComposer.getTypedWord().equals(wordBeforeCursor)) {
+ if (originallyTypedWord.equals(wordBeforeCursor)) {
throw new RuntimeException("cancelAutoCorrect check failed: we wanted to cancel "
- + "auto correction and revert to \"" + mWordComposer.getTypedWord()
+ + "auto correction and revert to \"" + originallyTypedWord
+ "\" but we found this very string before the cursor");
}
}
ic.deleteSurroundingText(cancelLength + 1, 0);
-
+ ic.commitText(originallyTypedWord, 1);
// Re-insert the separator
- ic.commitText(mWordComposer.getTypedWord(), 1);
ic.commitText(separator, 1);
+ mWordComposer.deleteAutoCorrection();
+ mWordComposer.onCommitWord();
Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE,
WordComposer.NOT_A_COORDINATE);
mHandler.cancelUpdateBigramPredictions();
@@ -2232,7 +2146,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// Note: in the interest of code simplicity, we may want to just call
// restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving
// the old WordComposer allows to reuse the actual typed coordinates.
- mHasUncommittedTypedChars = true;
+ mWordComposer.resumeSuggestionOnKeptWord();
ic.setComposingText(mWordComposer.getTypedWord(), 1);
mHandler.cancelUpdateBigramPredictions();
mHandler.postUpdateSuggestions();
@@ -2418,13 +2332,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private void updateCorrectionMode() {
// TODO: cleanup messy flags
final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
- && !mInputTypeNoAutoCorrect;
+ && !mInputAttributes.mInputTypeNoAutoCorrect;
mCorrectionMode = shouldAutoCorrect ? Suggest.CORRECTION_FULL : Suggest.CORRECTION_NONE;
mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect)
? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
}
- private void updateSuggestionVisibility(final SharedPreferences prefs, final Resources res) {
+ private void updateSuggestionVisibility(final Resources res) {
final String suggestionVisiblityStr = mSettingsValues.mShowSuggestionsSetting;
for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
if (suggestionVisiblityStr.equals(res.getString(visibility))) {
@@ -2514,17 +2428,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final Printer p = new PrintWriterPrinter(fout);
p.println("LatinIME state :");
- final Keyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
+ final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1;
p.println(" Keyboard mode = " + keyboardMode);
- p.println(" mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
+ p.println(" mIsSuggestionsRequested=" + mInputAttributes.mIsSettingsSuggestionStripOn);
p.println(" mCorrectionMode=" + mCorrectionMode);
- p.println(" mHasUncommittedTypedChars=" + mHasUncommittedTypedChars);
+ p.println(" isComposingWord=" + mWordComposer.isComposingWord());
p.println(" mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled);
- p.println(" mInsertSpaceOnPickSuggestionManually=" + mInsertSpaceOnPickSuggestionManually);
- p.println(" mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
p.println(" mSoundOn=" + mSettingsValues.mSoundOn);
p.println(" mVibrateOn=" + mSettingsValues.mVibrateOn);
p.println(" mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn);
+ p.println(" mInputAttributes=" + mInputAttributes.toString());
}
}
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
index da5058dd4..6f1adfe71 100644
--- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -29,6 +29,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static boolean sDBG = false;
public static boolean sVISUALDEBUG = false;
+ public static boolean sUsabilityStudy = false;
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 0ad1c1529..651d90ca4 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -52,7 +52,9 @@ public class SettingsValues {
private final String mVoiceMode;
private final String mAutoCorrectionThresholdRawValue;
public final String mShowSuggestionsSetting;
+ @SuppressWarnings("unused") // TODO: Use this
private final boolean mUsabilityStudyMode;
+ @SuppressWarnings("unused") // TODO: Use this
private final String mKeyPreviewPopupDismissDelayRawValue;
public final boolean mUseContactsDict;
// Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
@@ -60,7 +62,9 @@ public class SettingsValues {
// Prediction: use bigrams to predict the next word when there is no input for it yet
public final boolean mBigramPredictionEnabled;
public final boolean mEnableSuggestionSpanInsertion;
+ @SuppressWarnings("unused") // TODO: Use this
private final int mVibrationDurationSettingsRawValue;
+ @SuppressWarnings("unused") // TODO: Use this
private final float mKeypressSoundVolumeRawValue;
// Deduced settings
@@ -111,12 +115,12 @@ public class SettingsValues {
res.getString(R.string.auto_correction_threshold_mode_index_modest));
mShowSuggestionsSetting = prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING,
res.getString(R.string.prefs_suggestion_visibility_default_value));
- mUsabilityStudyMode = getUsabilityStudyMode(prefs, res);
+ mUsabilityStudyMode = getUsabilityStudyMode(prefs);
mKeyPreviewPopupDismissDelayRawValue = prefs.getString(
Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
Integer.toString(res.getInteger(R.integer.config_delay_after_preview)));
mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
- mAutoCorrectEnabled = isAutoCorrectEnabled(prefs, res, mAutoCorrectionThresholdRawValue);
+ mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue);
mBigramSuggestionEnabled = mAutoCorrectEnabled
&& isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled);
mBigramPredictionEnabled = mBigramSuggestionEnabled
@@ -131,7 +135,7 @@ public class SettingsValues {
mKeypressVibrationDuration = getCurrentVibrationDuration(prefs, res);
mFxVolume = getCurrentKeypressSoundVolume(prefs, res);
mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res);
- mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res,
+ mAutoCorrectionThreshold = getAutoCorrectionThreshold(res,
mAutoCorrectionThresholdRawValue);
mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff);
mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
@@ -202,8 +206,8 @@ public class SettingsValues {
return mMagicSpaceSwappers.contains(String.valueOf((char)code));
}
- private static boolean isAutoCorrectEnabled(final SharedPreferences sp,
- final Resources resources, final String currentAutoCorrectionSetting) {
+ private static boolean isAutoCorrectEnabled(final Resources resources,
+ final String currentAutoCorrectionSetting) {
final String autoCorrectionOff = resources.getString(
R.string.auto_correction_threshold_mode_index_off);
return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
@@ -244,8 +248,8 @@ public class SettingsValues {
R.bool.config_default_bigram_prediction));
}
- private static double getAutoCorrectionThreshold(final SharedPreferences sp,
- final Resources resources, final String currentAutoCorrectionSetting) {
+ private static double getAutoCorrectionThreshold(final Resources resources,
+ final String currentAutoCorrectionSetting) {
final String[] autoCorrectionThresholdValues = resources.getStringArray(
R.array.auto_correction_threshold_values);
// When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off.
@@ -321,8 +325,7 @@ public class SettingsValues {
}
// Likewise
- public static boolean getUsabilityStudyMode(final SharedPreferences prefs,
- final Resources res) {
+ public static boolean getUsabilityStudyMode(final SharedPreferences prefs) {
// TODO: use mUsabilityStudyMode instead of reading it again here
return prefs.getBoolean(Settings.PREF_USABILITY_STUDY_MODE, true);
}
diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java
index 6af20c754..a7f57ae46 100644
--- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java
@@ -172,7 +172,7 @@ public class UserUnigramDictionary extends ExpandableDictionary {
// Nothing pending? Return
if (mPendingWrites.isEmpty()) return;
// Create a background thread to write the pending entries
- new UpdateDbTask(getContext(), sOpenHelper, mPendingWrites, mLocale).execute();
+ new UpdateDbTask(sOpenHelper, mPendingWrites, mLocale).execute();
// Create a new map for writing new entries into while the old one is written to db
mPendingWrites = new HashMap<String, Integer>();
}
@@ -227,8 +227,8 @@ public class UserUnigramDictionary extends ExpandableDictionary {
private final DatabaseHelper mDbHelper;
private final String mLocale;
- public UpdateDbTask(@SuppressWarnings("unused") Context context, DatabaseHelper openHelper,
- HashMap<String, Integer> pendingWrites, String locale) {
+ public UpdateDbTask(DatabaseHelper openHelper, HashMap<String, Integer> pendingWrites,
+ String locale) {
mMap = pendingWrites;
mLocale = locale;
mDbHelper = openHelper;
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 60a9685bc..54d908011 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,10 +16,11 @@
package com.android.inputmethod.latin;
-import com.android.inputmethod.keyboard.Keyboard;
+import android.text.TextUtils;
+
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.KeyDetector;
-import com.android.inputmethod.keyboard.LatinKeyboard;
+import com.android.inputmethod.keyboard.Keyboard;
import java.util.ArrayList;
import java.util.Arrays;
@@ -41,12 +42,14 @@ public class WordComposer {
int[] mXCoordinates;
int[] mYCoordinates;
StringBuilder mTypedWord;
+ CharSequence mAutoCorrection;
CharacterStore() {
final int N = BinaryDictionary.MAX_WORD_LENGTH;
mCodes = new ArrayList<int[]>(N);
mTypedWord = new StringBuilder(N);
mXCoordinates = new int[N];
mYCoordinates = new int[N];
+ mAutoCorrection = null;
}
CharacterStore(final CharacterStore that) {
mCodes = new ArrayList<int[]>(that.mCodes);
@@ -58,16 +61,14 @@ public class WordComposer {
// For better performance than creating a new character store.
mCodes.clear();
mTypedWord.setLength(0);
+ mAutoCorrection = null;
}
}
- // The currently typing word.
- // NOTE: this is not reset as soon as the word is committed because it may be needed again
- // to resume suggestion if backspaced. TODO: separate cleanly what is actually being
- // composed and what is kept for possible resuming.
+ // The currently typing word. May not be null.
private CharacterStore mCurrentWord;
- // An auto-correction for this word out of the dictionary.
- private CharSequence mAutoCorrection;
+ // The information being kept for resuming suggestion. May be null if wiped.
+ private CharacterStore mCommittedWordSavedForSuggestionResuming;
private int mCapsCount;
@@ -82,8 +83,8 @@ public class WordComposer {
public WordComposer() {
mCurrentWord = new CharacterStore();
+ mCommittedWordSavedForSuggestionResuming = null;
mTrailingSingleQuotesCount = 0;
- mAutoCorrection = null;
}
public WordComposer(WordComposer source) {
@@ -92,11 +93,11 @@ public class WordComposer {
public void init(WordComposer source) {
mCurrentWord = new CharacterStore(source.mCurrentWord);
+ mCommittedWordSavedForSuggestionResuming = source.mCommittedWordSavedForSuggestionResuming;
mCapsCount = source.mCapsCount;
mIsFirstCharCapitalized = source.mIsFirstCharCapitalized;
mAutoCapitalized = source.mAutoCapitalized;
mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount;
- mAutoCorrection = null;
}
/**
@@ -104,10 +105,10 @@ public class WordComposer {
*/
public void reset() {
mCurrentWord.reset();
+ mCommittedWordSavedForSuggestionResuming = null;
mCapsCount = 0;
mIsFirstCharCapitalized = false;
mTrailingSingleQuotesCount = 0;
- mAutoCorrection = null;
}
/**
@@ -118,6 +119,10 @@ public class WordComposer {
return mCurrentWord.mTypedWord.length();
}
+ public final boolean isComposingWord() {
+ return size() > 0;
+ }
+
/**
* Returns the codes at a particular position in the word.
* @param index the position in the word
@@ -162,13 +167,13 @@ public class WordComposer {
} else {
mTrailingSingleQuotesCount = 0;
}
- mAutoCorrection = null;
+ mCurrentWord.mAutoCorrection = null;
}
/**
* Internal method to retrieve reasonable proximity info for a character.
*/
- private void addKeyInfo(final int codePoint, final LatinKeyboard keyboard,
+ private void addKeyInfo(final int codePoint, final Keyboard keyboard,
final KeyDetector keyDetector) {
for (final Key key : keyboard.mKeys) {
if (key.mCode == codePoint) {
@@ -188,7 +193,7 @@ public class WordComposer {
* Set the currently composing word to the one passed as an argument.
* This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity.
*/
- public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard,
+ public void setComposingWord(final CharSequence word, final Keyboard keyboard,
final KeyDetector keyDetector) {
reset();
final int length = word.length();
@@ -196,13 +201,13 @@ public class WordComposer {
int codePoint = word.charAt(i);
addKeyInfo(codePoint, keyboard, keyDetector);
}
- mAutoCorrection = null;
+ mCommittedWordSavedForSuggestionResuming = null;
}
/**
* Shortcut for the above method, this will create a new KeyDetector for the passed keyboard.
*/
- public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard) {
+ public void setComposingWord(final CharSequence word, final Keyboard keyboard) {
final KeyDetector keyDetector = new KeyDetector(0);
keyDetector.setKeyboard(keyboard, 0, 0);
keyDetector.setProximityCorrectionEnabled(true);
@@ -248,7 +253,7 @@ public class WordComposer {
++mTrailingSingleQuotesCount;
}
}
- mAutoCorrection = null;
+ mCurrentWord.mAutoCorrection = null;
}
/**
@@ -307,20 +312,44 @@ public class WordComposer {
* Sets the auto-correction for this word.
*/
public void setAutoCorrection(final CharSequence correction) {
- mAutoCorrection = correction;
+ mCurrentWord.mAutoCorrection = correction;
}
/**
* Remove any auto-correction that may have been set.
*/
public void deleteAutoCorrection() {
- mAutoCorrection = null;
+ mCurrentWord.mAutoCorrection = null;
}
/**
* @return the auto-correction for this word, or null if none.
*/
public CharSequence getAutoCorrectionOrNull() {
- return mAutoCorrection;
+ return mCurrentWord.mAutoCorrection;
+ }
+
+ // TODO: pass the information about what was committed and how. Was it an auto-correction?
+ // Was it a completion? Was is what the user typed?
+ public void onCommitWord() {
+ mCommittedWordSavedForSuggestionResuming = mCurrentWord;
+ // TODO: improve performance by swapping buffers instead of creating a new object.
+ mCurrentWord = new CharacterStore();
+ }
+
+ public boolean hasWordKeptForSuggestionResuming() {
+ return null != mCommittedWordSavedForSuggestionResuming;
+ }
+
+ public void resumeSuggestionOnKeptWord() {
+ mCurrentWord = mCommittedWordSavedForSuggestionResuming;
+ mCommittedWordSavedForSuggestionResuming = null;
+ }
+
+ public boolean didAutoCorrectToAnotherWord() {
+ return null != mCommittedWordSavedForSuggestionResuming
+ && !TextUtils.isEmpty(mCommittedWordSavedForSuggestionResuming.mAutoCorrection)
+ && !TextUtils.equals(mCommittedWordSavedForSuggestionResuming.mTypedWord,
+ mCommittedWordSavedForSuggestionResuming.mAutoCorrection);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/XmlParseUtils.java b/java/src/com/android/inputmethod/latin/XmlParseUtils.java
index 170be347b..d747a024c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/XmlParseUtils.java
+++ b/java/src/com/android/inputmethod/latin/XmlParseUtils.java
@@ -14,7 +14,7 @@
* the License.
*/
-package com.android.inputmethod.keyboard.internal;
+package com.android.inputmethod.latin;
import android.content.res.TypedArray;
@@ -47,14 +47,14 @@ public class XmlParseUtils {
}
@SuppressWarnings("serial")
- static class IllegalAttribute extends ParseException {
+ public static class IllegalAttribute extends ParseException {
public IllegalAttribute(XmlPullParser parser, String attribute) {
super("Tag " + parser.getName() + " has illegal attribute " + attribute, parser);
}
}
@SuppressWarnings("serial")
- static class NonEmptyTag extends ParseException{
+ public static class NonEmptyTag extends ParseException{
public NonEmptyTag(String tag, XmlPullParser parser) {
super(tag + " must be empty tag", parser);
}
diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 86072b64b..3d26d972d 100644
--- a/java/src/com/android/inputmethod/latin/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -14,7 +14,7 @@
* the License.
*/
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.suggestions;
import android.content.res.Resources;
import android.graphics.Paint;
@@ -25,26 +25,27 @@ import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
-import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
-import com.android.inputmethod.keyboard.internal.KeyboardParams;
+import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
public class MoreSuggestions extends Keyboard {
- private static final boolean DBG = LatinImeLogger.sDBG;
-
public static final int SUGGESTION_CODE_BASE = 1024;
private MoreSuggestions(Builder.MoreSuggestionsParam params) {
super(params);
}
- public static class Builder extends KeyboardBuilder<Builder.MoreSuggestionsParam> {
+ public static class Builder extends Keyboard.Builder<Builder.MoreSuggestionsParam> {
+ private static final boolean DBG = LatinImeLogger.sDBG;
+
private final MoreSuggestionsView mPaneView;
private SuggestedWords mSuggestions;
private int mFromPos;
private int mToPos;
- public static class MoreSuggestionsParam extends KeyboardParams {
+ public static class MoreSuggestionsParam extends Keyboard.Params {
private final int[] mWidths = new int[SuggestionsView.MAX_SUGGESTIONS];
private final int[] mRowNumbers = new int[SuggestionsView.MAX_SUGGESTIONS];
private final int[] mColumnOrders = new int[SuggestionsView.MAX_SUGGESTIONS];
@@ -176,9 +177,9 @@ public class MoreSuggestions extends Keyboard {
public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth,
int minWidth, int maxRow) {
- final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard();
+ final Keyboard keyboard = KeyboardSwitcher.getInstance().getKeyboard();
final int xmlId = R.xml.kbd_suggestions_pane_template;
- load(keyboard.mId.cloneWithNewXml(xmlId));
+ load(xmlId, keyboard.mId);
mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2;
final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow,
diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
index c61dd6313..b5f67ace0 100644
--- a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.suggestions;
import android.content.Context;
import android.content.res.Resources;
@@ -34,6 +34,7 @@ import com.android.inputmethod.keyboard.PointerTracker;
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
+import com.android.inputmethod.latin.R;
/**
* A view that renders a virtual {@link MoreSuggestions}. It handles rendering of keys and detecting
diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
index dbd4677f0..40d782640 100644
--- a/java/src/com/android/inputmethod/latin/SuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
@@ -14,7 +14,7 @@
* the License.
*/
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.suggestions;
import android.content.Context;
import android.content.res.Resources;
@@ -57,7 +57,12 @@ import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.MoreKeysPanel;
import com.android.inputmethod.keyboard.PointerTracker;
+import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -72,7 +77,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
// The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
public static final int MAX_SUGGESTIONS = 18;
- private static final boolean DBG = LatinImeLogger.sDBG;
+ static final boolean DBG = LatinImeLogger.sDBG;
private final ViewGroup mSuggestionsStrip;
private KeyboardView mKeyboardView;
@@ -100,8 +105,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
private static class UiHandler extends StaticInnerHandlerWrapper<SuggestionsView> {
private static final int MSG_HIDE_PREVIEW = 0;
- private static final long DELAY_HIDE_PREVIEW = 1300;
-
public UiHandler(SuggestionsView outerInstance) {
super(outerInstance);
}
@@ -116,11 +119,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
}
}
- public void postHidePreview() {
- cancelHidePreview();
- sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
- }
-
public void cancelHidePreview() {
removeMessages(MSG_HIDE_PREVIEW);
}
@@ -148,6 +146,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
private final List<View> mDividers;
private final List<TextView> mInfos;
+ private final int mColorValidTypedWord;
private final int mColorTypedWord;
private final int mColorAutoCorrect;
private final int mColorSuggested;
@@ -191,6 +190,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SuggestionsView, defStyle, R.style.SuggestionsViewStyle);
mSuggestionStripOption = a.getInt(R.styleable.SuggestionsView_suggestionStripOption, 0);
+ final float alphaValidTypedWord = getPercent(a,
+ R.styleable.SuggestionsView_alphaValidTypedWord, 100);
final float alphaTypedWord = getPercent(a,
R.styleable.SuggestionsView_alphaTypedWord, 100);
final float alphaAutoCorrect = getPercent(a,
@@ -198,6 +199,9 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
final float alphaSuggested = getPercent(a,
R.styleable.SuggestionsView_alphaSuggested, 100);
mAlphaObsoleted = getPercent(a, R.styleable.SuggestionsView_alphaSuggested, 100);
+ mColorValidTypedWord = applyAlpha(
+ a.getColor(R.styleable.SuggestionsView_colorValidTypedWord, 0),
+ alphaValidTypedWord);
mColorTypedWord = applyAlpha(
a.getColor(R.styleable.SuggestionsView_colorTypedWord, 0), alphaTypedWord);
mColorAutoCorrect = applyAlpha(
@@ -295,6 +299,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
final int color;
if (index == mCenterSuggestionIndex && Utils.willAutoCorrect(suggestions)) {
color = mColorAutoCorrect;
+ } else if (index == mCenterSuggestionIndex && suggestions.mTypedWordValid) {
+ color = mColorValidTypedWord;
} else if (isSuggested) {
color = mColorSuggested;
} else {
@@ -430,7 +436,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
final TextView word = mWords.get(index);
word.setEnabled(true);
- word.setTextColor(mColorTypedWord);
+ word.setTextColor(mColorAutoCorrect);
final CharSequence text = suggestions.getWord(index);
word.setText(text);
word.setTextScaleX(1.0f);