diff --git a/java/res/values-cs/donottranslate-altchars.xml b/java/res/values-cs/donottranslate-altchars.xml index d91a0e449..f19ac0026 100644 --- a/java/res/values-cs/donottranslate-altchars.xml +++ b/java/res/values-cs/donottranslate-altchars.xml @@ -18,17 +18,16 @@ */ --> - áàâãäåæ - 3éěèêë - íìîï8 - óòôõöœø9 - ůúùûü7 - š§ß - ňñ - čç - ýÿ6 + á,à,â,ã,ä,å,æ + 3,é,ě,è,ê,ë + í,ì,î,ï,8 + ó,ò,ô,õ,ö,œ,ø,9 + ů,ú,ù,û,ü,7 + š,§,ß + ň,ñ + č,ç ď - ř4 - ť5 + ř,4 + ť,5 ž diff --git a/java/res/values-da/donottranslate-altchars.xml b/java/res/values-da/donottranslate-altchars.xml index 596994ca4..ca1df7c25 100644 --- a/java/res/values-da/donottranslate-altchars.xml +++ b/java/res/values-da/donottranslate-altchars.xml @@ -18,23 +18,23 @@ */ --> - áàâąã - 3éèêëę€ - íìîï8 - óòôõ9 - úùûū7 - śšşß - ńñň - çćč - ýÿü6 - ðď - ř4 - ťþ5 - źžż + á,à,â,ą,ã + 3,é,è,ê,ë,ę,€ + í,ì,î,ï,8 + ó,ò,ô,õ,9 + ú,ù,û,ū,7 + ś,š,ş,ß + ń,ñ,ň + ç,ć,č + ý,ÿ,ü,6 + ð,ď + ř,4 + ť,þ,5 + ź,ž,ż ł w æ ø ä - öœ + ö,œ diff --git a/java/res/values-de/donottranslate-altchars.xml b/java/res/values-de/donottranslate-altchars.xml index df27bce28..6c1abc6d0 100644 --- a/java/res/values-de/donottranslate-altchars.xml +++ b/java/res/values-de/donottranslate-altchars.xml @@ -19,13 +19,7 @@ --> ä - 3èéêë - ìíîï8 - ö9 - ùúûü7 - §ß - ñ - ç - ýÿ + ö,9 + ý,ÿ 6 diff --git a/java/res/values-el/donottranslate-altchars.xml b/java/res/values-el/donottranslate-altchars.xml deleted file mode 100644 index d3beafade..000000000 --- a/java/res/values-el/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - 3èéêë - ìíîï8 - òóôõöœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 - diff --git a/java/res/values-en/donottranslate-altchars.xml b/java/res/values-en/donottranslate-altchars.xml index 083befa19..baded885a 100644 --- a/java/res/values-en/donottranslate-altchars.xml +++ b/java/res/values-en/donottranslate-altchars.xml @@ -18,10 +18,9 @@ */ --> - àáâãäåāæ - 3èéêëē - ìíîïī8 - òóôõöōœø9 - ùúûüū7 - ýÿ6 + à,á,â,ã,ä,å,ā,æ + 3,è,é,ê,ë,ē + ì,í,î,ï,ī,8 + ò,ó,ô,õ,ö,ō,œ,ø,9 + ù,ú,û,ü,ū,7 diff --git a/java/res/values-es-rUS/donottranslate-altchars.xml b/java/res/values-es-rUS/donottranslate-altchars.xml deleted file mode 100644 index d3beafade..000000000 --- a/java/res/values-es-rUS/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - 3èéêë - ìíîï8 - òóôõöœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 - diff --git a/java/res/values-es/donottranslate-altchars.xml b/java/res/values-es/donottranslate-altchars.xml index 721062d2d..35187d0de 100644 --- a/java/res/values-es/donottranslate-altchars.xml +++ b/java/res/values-es/donottranslate-altchars.xml @@ -19,12 +19,6 @@ --> á - - ìíîï8 - ó9 - ùúûü7 - §ß - ñ - ç - ýÿ6 + 3,é + ó,9 diff --git a/java/res/values-fr/donottranslate-altchars.xml b/java/res/values-fr/donottranslate-altchars.xml index 874d89dab..830119d52 100644 --- a/java/res/values-fr/donottranslate-altchars.xml +++ b/java/res/values-fr/donottranslate-altchars.xml @@ -18,15 +18,7 @@ */ --> - 1àáâãäåæ - 3èéêë - ìíîï8 - òóôõöœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 + 1,à,á,â,ã,ä,å,æ 2 diff --git a/java/res/values-it/donottranslate-altchars.xml b/java/res/values-it/donottranslate-altchars.xml index 23960171b..0e4a285f1 100644 --- a/java/res/values-it/donottranslate-altchars.xml +++ b/java/res/values-it/donottranslate-altchars.xml @@ -18,13 +18,8 @@ */ --> - àá - 3èé - ìíîï8 - òó9 - ùúûü7 + à,á + 3,è,é + ò,ó,9 § - ñ - ç - ýÿ6 diff --git a/java/res/values-ja/donottranslate-altchars.xml b/java/res/values-ja/donottranslate-altchars.xml deleted file mode 100644 index d3beafade..000000000 --- a/java/res/values-ja/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - 3èéêë - ìíîï8 - òóôõöœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 - diff --git a/java/res/values-ko/donottranslate-altchars.xml b/java/res/values-ko/donottranslate-altchars.xml deleted file mode 100644 index d3beafade..000000000 --- a/java/res/values-ko/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - 3èéêë - ìíîï8 - òóôõöœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 - diff --git a/java/res/values-nb/donottranslate-altchars.xml b/java/res/values-nb/donottranslate-altchars.xml index 264402987..c65dea9fb 100644 --- a/java/res/values-nb/donottranslate-altchars.xml +++ b/java/res/values-nb/donottranslate-altchars.xml @@ -18,19 +18,18 @@ */ --> - äáàâąã - 3éèêëę€ - íìîï8 - öóòôõ9 - üúùûū7 - śšşß - ńñň - çćč - ýÿ6 - ðď - ř4 - ťþ5 - źžż + ä,á,à,â,ą,ã + 3,é,è,ê,ë,ę,€ + í,ì,î,ï,8 + ö,ó,ò,ô,õ,9 + ü,ú,ù,û,ū,7 + ś,š,ş,ß + ń,ñ,ň + ç,ć,č + ð,ď + ř,4 + ť,þ,5 + ź,ž,ż ł w ø diff --git a/java/res/values-nl/donottranslate-altchars.xml b/java/res/values-nl/donottranslate-altchars.xml deleted file mode 100644 index d3beafade..000000000 --- a/java/res/values-nl/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - 3èéêë - ìíîï8 - òóôõöœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 - diff --git a/java/res/values-pl/donottranslate-altchars.xml b/java/res/values-pl/donottranslate-altchars.xml index da6b5fd5c..df8c52b47 100644 --- a/java/res/values-pl/donottranslate-altchars.xml +++ b/java/res/values-pl/donottranslate-altchars.xml @@ -19,14 +19,11 @@ --> ą - ę3 - ìíîï8 - ó9 - ùúûü7 + ę,3 + ó,9 ś ń ć - ýÿ6 - źż + ź,ż ł diff --git a/java/res/values-pt-rPT/donottranslate-altchars.xml b/java/res/values-pt-rPT/donottranslate-altchars.xml deleted file mode 100644 index d3beafade..000000000 --- a/java/res/values-pt-rPT/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - 3èéêë - ìíîï8 - òóôõöœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 - diff --git a/java/res/values-pt/donottranslate-altchars.xml b/java/res/values-pt/donottranslate-altchars.xml deleted file mode 100644 index d3beafade..000000000 --- a/java/res/values-pt/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - 3èéêë - ìíîï8 - òóôõöœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 - diff --git a/java/res/values-rm/donottranslate-altchars.xml b/java/res/values-rm/donottranslate-altchars.xml index f17026fa9..b44c3c005 100644 --- a/java/res/values-rm/donottranslate-altchars.xml +++ b/java/res/values-rm/donottranslate-altchars.xml @@ -18,13 +18,5 @@ */ --> - àáâãäåæ - 3èéêë - ìíîï8 - òóöôõœø9 - ùúûü7 - §ß - ñ - ç - ýÿ6 + ò,ó,ö,ô,õ,œ,ø,9 diff --git a/java/res/values-ru/donottranslate-altchars.xml b/java/res/values-ru/donottranslate-altchars.xml index 46241a62a..c4f9d66d3 100644 --- a/java/res/values-ru/donottranslate-altchars.xml +++ b/java/res/values-ru/donottranslate-altchars.xml @@ -18,15 +18,6 @@ */ --> - àáâãäåæ - èéêë - ìíîï - òóôõöœø - ùúûü - §ß - ñ - ç - ýÿ ё5 ъ diff --git a/java/res/values-sv/donottranslate-altchars.xml b/java/res/values-sv/donottranslate-altchars.xml index 902a4c9bb..e156de896 100644 --- a/java/res/values-sv/donottranslate-altchars.xml +++ b/java/res/values-sv/donottranslate-altchars.xml @@ -18,23 +18,23 @@ */ --> - áàâąã - 3éèêëę€ - íìîï8 - óòôõ9 - úùûū7 - śšşß - ńñň - çćč - ýÿü6 - ðď - ř4 - ťþ5 - źžż + á,à,â,ą,ã + 3,é,è,ê,ë,ę,€ + í,ì,î,ï,8 + ó,ò,ô,õ,9 + ú,ù,û,ū,7 + ś,š,ş,ß + ń,ñ,ň + ç,ć,č + ý,ÿ,ü,6 + ð,ď + ř,4 + ť,þ,5 + ź,ž,ż ł w ö ä - øœ + ø,œ æ diff --git a/java/res/values-tr/donottranslate-altchars.xml b/java/res/values-tr/donottranslate-altchars.xml index 4200d949e..5e98cc30e 100644 --- a/java/res/values-tr/donottranslate-altchars.xml +++ b/java/res/values-tr/donottranslate-altchars.xml @@ -18,14 +18,8 @@ */ --> - àáâãäåæ - 3èéêë - ìíîï8 - öòóôõœø9 - üùúû7 - ş§ß - ñ - ç - ýÿ6 + ö,ò,ó,ô,õ,œ,ø,9 + ü,ù,ú,û,7 + ş,§,ß ğ - \ No newline at end of file + diff --git a/java/res/values-xlarge/bools.xml b/java/res/values-xlarge/bools.xml deleted file mode 100644 index 9fb670c54..000000000 --- a/java/res/values-xlarge/bools.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - false - false - false - false - false - diff --git a/java/res/values-xlarge/config.xml b/java/res/values-xlarge/config.xml index 0a1d4e48d..26c23dd1c 100644 --- a/java/res/values-xlarge/config.xml +++ b/java/res/values-xlarge/config.xml @@ -19,5 +19,12 @@ --> + false + false + false + false + + false medium + 9 diff --git a/java/res/values-zh-rCN/donottranslate-altchars.xml b/java/res/values-zh-rCN/donottranslate-altchars.xml deleted file mode 100644 index c165b11c5..000000000 --- a/java/res/values-zh-rCN/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - èéêë - ìíîï - òóôõöœø - ùúûü - §ß - ñ - ç - ýÿ - diff --git a/java/res/values-zh-rTW/donottranslate-altchars.xml b/java/res/values-zh-rTW/donottranslate-altchars.xml deleted file mode 100644 index c165b11c5..000000000 --- a/java/res/values-zh-rTW/donottranslate-altchars.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - àáâãäåæ - èéêë - ìíîï - òóôõöœø - ùúûü - §ß - ñ - ç - ýÿ - diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 55c806ca4..549c2ae81 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -89,15 +89,17 @@ + + - - + + diff --git a/java/res/values/bools.xml b/java/res/values/bools.xml index 8742676ad..2a181e17d 100644 --- a/java/res/values/bools.xml +++ b/java/res/values/bools.xml @@ -18,20 +18,9 @@ */ --> - - true false true - true - - true - true - true - true - true - true - true diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 14b8d0060..d82960e15 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -19,6 +19,15 @@ --> + true + true + true + true + true + true + true + + true 0 10 0 @@ -33,6 +42,9 @@ 1200 800 small + 9 + + true diff --git a/java/res/values/donottranslate-altchars.xml b/java/res/values/donottranslate-altchars.xml index de4250edf..85e06f23b 100644 --- a/java/res/values/donottranslate-altchars.xml +++ b/java/res/values/donottranslate-altchars.xml @@ -18,15 +18,15 @@ */ --> - àáâãäåæ - èéêë - ìíîï - òóôõöœø - ùúûü - §ß + à,á,â,ã,ä,å,æ + 3,è,é,ê,ë + ì,í,î,ï,8 + ò,ó,ô,õ,ö,œ,ø,9 + ù,ú,û,ü,7 + §,ß ñ ç - ýÿ + ý,ÿ,6 1 2 @@ -43,14 +43,13 @@ + "\@drawable/sym_keyboard_settings|\@integer/key_settings,\@drawable/sym_keyboard_mic|\@integer/key_voice" + ":-)|:-) ,:-(|:-( ,;-)|;-) ,:-P|:-P ,=-O|=-O ,:-*|:-* ,:O|:O ,B-)|B-) ,:-$|:-$ ,:-!|:-! ,:-[|:-[ ,O:-)|O:-) ,:-\\\\\\\\|:-\\\\\\\\ ,:\'(|:\'( ,:-D|:-D " + "\@drawable/sym_keyboard_settings|\@integer/key_settings,/" + "\@drawable/sym_keyboard_settings|\@integer/key_settings,\@" + "\@drawable/sym_keyboard_settings|\@integer/key_settings,\\," + ":,/,&,(,),-,+,;,\@,\',\",\?,!,\\," + ".com" - ".com" - - ".net" - - ".org" - - ".gov" - - ".edu" + ".net,.org,.gov,.edu" diff --git a/java/res/xml-da-xlarge/kbd_qwerty.xml b/java/res/xml-da-xlarge/kbd_qwerty.xml index 2852c765a..aa868e453 100644 --- a/java/res/xml-da-xlarge/kbd_qwerty.xml +++ b/java/res/xml-da-xlarge/kbd_qwerty.xml @@ -31,6 +31,8 @@ latin:rowHeight="25%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-da/kbd_qwerty.xml b/java/res/xml-da/kbd_qwerty.xml index 43215de2d..dfca1cdd2 100644 --- a/java/res/xml-da/kbd_qwerty.xml +++ b/java/res/xml-da/kbd_qwerty.xml @@ -32,6 +32,8 @@ latin:keyWidth="9.09%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-de-xlarge/kbd_qwerty.xml b/java/res/xml-de-xlarge/kbd_qwerty.xml index 3c92b29a1..a23e4fbf0 100644 --- a/java/res/xml-de-xlarge/kbd_qwerty.xml +++ b/java/res/xml-de-xlarge/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-de/kbd_qwerty.xml b/java/res/xml-de/kbd_qwerty.xml index 3c92b29a1..a23e4fbf0 100644 --- a/java/res/xml-de/kbd_qwerty.xml +++ b/java/res/xml-de/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-fr-rCA-xlarge/kbd_qwerty.xml b/java/res/xml-fr-rCA-xlarge/kbd_qwerty.xml index b102eb603..92d92f0e6 100644 --- a/java/res/xml-fr-rCA-xlarge/kbd_qwerty.xml +++ b/java/res/xml-fr-rCA-xlarge/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-fr-rCA/kbd_qwerty.xml b/java/res/xml-fr-rCA/kbd_qwerty.xml index b102eb603..92d92f0e6 100644 --- a/java/res/xml-fr-rCA/kbd_qwerty.xml +++ b/java/res/xml-fr-rCA/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-fr-rCH-xlarge/kbd_qwerty.xml b/java/res/xml-fr-rCH-xlarge/kbd_qwerty.xml index 3c92b29a1..a23e4fbf0 100644 --- a/java/res/xml-fr-rCH-xlarge/kbd_qwerty.xml +++ b/java/res/xml-fr-rCH-xlarge/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-fr-rCH/kbd_qwerty.xml b/java/res/xml-fr-rCH/kbd_qwerty.xml index 3c92b29a1..a23e4fbf0 100644 --- a/java/res/xml-fr-rCH/kbd_qwerty.xml +++ b/java/res/xml-fr-rCH/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-fr-xlarge/kbd_qwerty.xml b/java/res/xml-fr-xlarge/kbd_qwerty.xml index a94384324..2d0b42baf 100644 --- a/java/res/xml-fr-xlarge/kbd_qwerty.xml +++ b/java/res/xml-fr-xlarge/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-fr/kbd_qwerty.xml b/java/res/xml-fr/kbd_qwerty.xml index a94384324..2d0b42baf 100644 --- a/java/res/xml-fr/kbd_qwerty.xml +++ b/java/res/xml-fr/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-iw/kbd_qwerty.xml b/java/res/xml-iw/kbd_qwerty.xml index 7d7774efe..98bfd7e0b 100644 --- a/java/res/xml-iw/kbd_qwerty.xml +++ b/java/res/xml-iw/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-nb-xlarge/kbd_qwerty.xml b/java/res/xml-nb-xlarge/kbd_qwerty.xml index e64796628..5dfdc4f56 100644 --- a/java/res/xml-nb-xlarge/kbd_qwerty.xml +++ b/java/res/xml-nb-xlarge/kbd_qwerty.xml @@ -31,6 +31,8 @@ latin:rowHeight="25%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-nb/kbd_qwerty.xml b/java/res/xml-nb/kbd_qwerty.xml index 2985354e5..06f1b947a 100644 --- a/java/res/xml-nb/kbd_qwerty.xml +++ b/java/res/xml-nb/kbd_qwerty.xml @@ -32,6 +32,8 @@ latin:keyWidth="9.09%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-ru-xlarge/kbd_qwerty.xml b/java/res/xml-ru-xlarge/kbd_qwerty.xml index 10f02415b..b86002a31 100644 --- a/java/res/xml-ru-xlarge/kbd_qwerty.xml +++ b/java/res/xml-ru-xlarge/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="9.091%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > @@ -40,43 +42,33 @@ latin:keyEdgeFlags="left" /> @@ -141,7 +133,6 @@ latin:keyLabel="т" /> diff --git a/java/res/xml-ru/kbd_qwerty.xml b/java/res/xml-ru/kbd_qwerty.xml index b96c958c7..08d7a4ac5 100644 --- a/java/res/xml-ru/kbd_qwerty.xml +++ b/java/res/xml-ru/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="9.091%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > @@ -35,54 +37,44 @@ diff --git a/java/res/xml-sr-xlarge/kbd_qwerty.xml b/java/res/xml-sr-xlarge/kbd_qwerty.xml index 7290c13a0..48764e7c7 100644 --- a/java/res/xml-sr-xlarge/kbd_qwerty.xml +++ b/java/res/xml-sr-xlarge/kbd_qwerty.xml @@ -27,6 +27,8 @@ latin:keyWidth="9.09%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > @@ -41,43 +43,33 @@ latin:keyEdgeFlags="left" /> @@ -149,14 +141,12 @@ latin:manualTemporaryUpperCaseCode="33" latin:keyHintIcon="@drawable/key_hint_exclamation_holo" latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_exclamation_large_holo" - latin:popupKeyboard="@xml/kbd_popup_template" latin:popupCharacters="!" /> @@ -36,53 +38,43 @@ diff --git a/java/res/xml-sv/kbd_qwerty.xml b/java/res/xml-sv/kbd_qwerty.xml index b3d1b8784..60d3b45f9 100644 --- a/java/res/xml-sv/kbd_qwerty.xml +++ b/java/res/xml-sv/kbd_qwerty.xml @@ -34,6 +34,8 @@ latin:keyWidth="9.09%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-xlarge-land/popup_domains.xml b/java/res/xml-xlarge-land/popup_domains.xml deleted file mode 100644 index 03a3846f9..000000000 --- a/java/res/xml-xlarge-land/popup_domains.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-xlarge-land/popup_smileys.xml b/java/res/xml-xlarge-land/popup_smileys.xml deleted file mode 100644 index cc4acb06e..000000000 --- a/java/res/xml-xlarge-land/popup_smileys.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java/res/xml-xlarge/kbd_azerty_rows.xml b/java/res/xml-xlarge/kbd_azerty_rows.xml index b68e21481..616295065 100644 --- a/java/res/xml-xlarge/kbd_azerty_rows.xml +++ b/java/res/xml-xlarge/kbd_azerty_rows.xml @@ -33,43 +33,33 @@ latin:keyEdgeFlags="left" /> @@ -110,7 +96,6 @@ latin:keyLabel="k" /> diff --git a/java/res/xml-xlarge/kbd_key_styles.xml b/java/res/xml-xlarge/kbd_key_styles.xml index be4611195..6c1df0b9e 100644 --- a/java/res/xml-xlarge/kbd_key_styles.xml +++ b/java/res/xml-xlarge/kbd_key_styles.xml @@ -62,11 +62,11 @@ latin:iconPreview="@drawable/sym_keyboard_feedback_space" /> + latin:popupCharacters="@string/alternates_for_smiley" + latin:maxPopupKeyboardColumn="5" /> + latin:popupCharacters="@string/alternates_for_smiley" + latin:maxPopupKeyboardColumn="5" /> + latin:popupCharacters="@string/alternates_for_popular_domain" /> diff --git a/java/res/xml-xlarge/kbd_number.xml b/java/res/xml-xlarge/kbd_number.xml index 11cf8fb86..93bc1363a 100644 --- a/java/res/xml-xlarge/kbd_number.xml +++ b/java/res/xml-xlarge/kbd_number.xml @@ -26,6 +26,8 @@ latin:keyWidth="11.949%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-xlarge/kbd_phone.xml b/java/res/xml-xlarge/kbd_phone.xml index 6389a8ccd..66f602068 100644 --- a/java/res/xml-xlarge/kbd_phone.xml +++ b/java/res/xml-xlarge/kbd_phone.xml @@ -26,6 +26,8 @@ latin:keyWidth="11.949%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-xlarge/kbd_phone_symbols.xml b/java/res/xml-xlarge/kbd_phone_symbols.xml index 59d8181f6..8c0df030d 100644 --- a/java/res/xml-xlarge/kbd_phone_symbols.xml +++ b/java/res/xml-xlarge/kbd_phone_symbols.xml @@ -26,6 +26,8 @@ latin:keyWidth="11.949%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-xlarge/kbd_qwerty.xml b/java/res/xml-xlarge/kbd_qwerty.xml index 75fe183a3..1c8d51ffe 100644 --- a/java/res/xml-xlarge/kbd_qwerty.xml +++ b/java/res/xml-xlarge/kbd_qwerty.xml @@ -25,6 +25,8 @@ latin:rowHeight="25%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml-xlarge/kbd_qwerty_row1.xml b/java/res/xml-xlarge/kbd_qwerty_row1.xml index 159686792..f5135591c 100644 --- a/java/res/xml-xlarge/kbd_qwerty_row1.xml +++ b/java/res/xml-xlarge/kbd_qwerty_row1.xml @@ -32,43 +32,33 @@ latin:keyEdgeFlags="left" /> @@ -55,7 +51,6 @@ latin:keyLabel="k" /> @@ -65,14 +61,12 @@ latin:manualTemporaryUpperCaseCode="33" latin:keyHintIcon="@drawable/key_hint_exclamation_holo" latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_exclamation_large_holo" - latin:popupKeyboard="@xml/kbd_popup_template" latin:popupCharacters="!" /> diff --git a/java/res/xml-xlarge/kbd_qwerty_row4.xml b/java/res/xml-xlarge/kbd_qwerty_row4.xml index 205f2e0e3..e222a6bb0 100644 --- a/java/res/xml-xlarge/kbd_qwerty_row4.xml +++ b/java/res/xml-xlarge/kbd_qwerty_row4.xml @@ -54,7 +54,6 @@ latin:manualTemporaryUpperCaseCode="43" latin:keyHintIcon="@drawable/key_hint_plus_holo" latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_plus_large_holo" - latin:popupKeyboard="@xml/kbd_popup_template" latin:popupCharacters="+" /> @@ -67,7 +66,6 @@ latin:manualTemporaryUpperCaseCode="64" latin:keyHintIcon="@drawable/key_hint_at_holo" latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_at_large_holo" - latin:popupKeyboard="@xml/kbd_popup_template" latin:popupCharacters="\@" /> @@ -89,7 +87,6 @@ latin:manualTemporaryUpperCaseCode="58" latin:keyHintIcon="@drawable/key_hint_colon_holo" latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_colon_large_holo" - latin:popupKeyboard="@xml/kbd_popup_template" latin:popupCharacters=":" /> @@ -98,7 +95,6 @@ latin:manualTemporaryUpperCaseCode="34" latin:keyHintIcon="@drawable/key_hint_quote_holo" latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_quote_large_holo" - latin:popupKeyboard="@xml/kbd_popup_template" latin:popupCharacters=""" /> @@ -115,7 +111,6 @@ latin:manualTemporaryUpperCaseCode="95" latin:keyHintIcon="@drawable/key_hint_underline_holo" latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_underline_large_holo" - latin:popupKeyboard="@xml/kbd_popup_template" latin:popupCharacters="_" /> diff --git a/java/res/xml-xlarge/kbd_qwerty_rows_scandinavia.xml b/java/res/xml-xlarge/kbd_qwerty_rows_scandinavia.xml index c56d4f497..8c583ba85 100644 --- a/java/res/xml-xlarge/kbd_qwerty_rows_scandinavia.xml +++ b/java/res/xml-xlarge/kbd_qwerty_rows_scandinavia.xml @@ -33,43 +33,33 @@ latin:keyEdgeFlags="left" /> @@ -88,21 +78,17 @@ latin:keyEdgeFlags="left" /> @@ -112,15 +98,12 @@ latin:keyLabel="k" /> @@ -122,14 +108,12 @@ latin:manualTemporaryUpperCaseCode="33" latin:keyHintIcon="@drawable/key_hint_exclamation_holo" latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_exclamation_large_holo" - latin:popupKeyboard="@xml/kbd_popup_template" latin:popupCharacters="!" /> diff --git a/java/res/xml-xlarge/kbd_symbols.xml b/java/res/xml-xlarge/kbd_symbols.xml index f78af8abd..50b8e5307 100644 --- a/java/res/xml-xlarge/kbd_symbols.xml +++ b/java/res/xml-xlarge/kbd_symbols.xml @@ -25,6 +25,8 @@ latin:rowHeight="25%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > @@ -39,29 +41,23 @@ latin:keyEdgeFlags="left" /> + latin:popupCharacters="¹,½,⅓,¼,⅛" /> + latin:popupCharacters="²,⅔" /> + latin:popupCharacters="³,¾,⅜" /> @@ -69,8 +65,7 @@ latin:keyLabel="9" /> + latin:popupCharacters="ⁿ,∅" /> + latin:popupCharacters="¢,£,€,¥,₣,₤,₱" /> + latin:popupCharacters="†,‡,★" /> + latin:popupCharacters="_,–,—" /> + latin:popupCharacters="[,{,<" /> + latin:popupCharacters="],},>" /> + latin:popupCharacters="≤,«,‹" /> + latin:popupCharacters="≥,»,›" /> + latin:popupCharacters="≠,≈" /> + latin:popupCharacters="“,”,«,»,˝" /> @@ -45,13 +47,11 @@ latin:keyLabel="|" /> + latin:popupCharacters="♪,♥,♠,♦,♣" /> @@ -59,7 +59,6 @@ latin:keyLabel="×" /> @@ -86,13 +85,11 @@ latin:keyLabel="¥" /> + latin:popupCharacters="↑,↓,←,→" /> diff --git a/java/res/xml-xlarge/popup_domains.xml b/java/res/xml-xlarge/popup_domains.xml deleted file mode 100644 index 6d65c898b..000000000 --- a/java/res/xml-xlarge/popup_domains.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml-xlarge/popup_smileys.xml b/java/res/xml-xlarge/popup_smileys.xml deleted file mode 100644 index 552dc42a7..000000000 --- a/java/res/xml-xlarge/popup_smileys.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java/res/xml/kbd_azerty_rows.xml b/java/res/xml/kbd_azerty_rows.xml index c06724c49..71109ab67 100644 --- a/java/res/xml/kbd_azerty_rows.xml +++ b/java/res/xml/kbd_azerty_rows.xml @@ -30,53 +30,43 @@ @@ -85,22 +75,18 @@ > @@ -110,7 +96,6 @@ latin:keyLabel="k" /> diff --git a/java/res/xml/kbd_key_styles.xml b/java/res/xml/kbd_key_styles.xml index 9dd166a41..3b6df7315 100644 --- a/java/res/xml/kbd_key_styles.xml +++ b/java/res/xml/kbd_key_styles.xml @@ -88,10 +88,10 @@ @@ -165,10 +165,10 @@ @@ -284,6 +284,7 @@ latin:keyLabel=":-)" latin:keyOutputText=":-) " latin:keyHintIcon="@drawable/hint_popup" - latin:popupKeyboard="@xml/popup_smileys" + latin:popupCharacters="@string/alternates_for_smiley" + latin:maxPopupKeyboardColumn="5" latin:parentStyle="functionalKeyStyle" /> \ No newline at end of file diff --git a/java/res/xml/kbd_number.xml b/java/res/xml/kbd_number.xml index f09da8683..f4a5def95 100644 --- a/java/res/xml/kbd_number.xml +++ b/java/res/xml/kbd_number.xml @@ -26,10 +26,12 @@ latin:keyWidth="26.67%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > - + diff --git a/java/res/xml/kbd_phone.xml b/java/res/xml/kbd_phone.xml index fb0e6d7f2..62fbdeeec 100644 --- a/java/res/xml/kbd_phone.xml +++ b/java/res/xml/kbd_phone.xml @@ -26,6 +26,8 @@ latin:keyWidth="26.67%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml/kbd_phone_symbols.xml b/java/res/xml/kbd_phone_symbols.xml index 5f75ecb53..1997a75fc 100644 --- a/java/res/xml/kbd_phone_symbols.xml +++ b/java/res/xml/kbd_phone_symbols.xml @@ -26,6 +26,8 @@ latin:keyWidth="26.67%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml/kbd_qwerty.xml b/java/res/xml/kbd_qwerty.xml index b102eb603..92d92f0e6 100644 --- a/java/res/xml/kbd_qwerty.xml +++ b/java/res/xml/kbd_qwerty.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > diff --git a/java/res/xml/kbd_qwerty_f1.xml b/java/res/xml/kbd_qwerty_f1.xml index 1f0ccfb98..cbdb8c09a 100644 --- a/java/res/xml/kbd_qwerty_f1.xml +++ b/java/res/xml/kbd_qwerty_f1.xml @@ -27,8 +27,8 @@ > @@ -53,8 +53,8 @@ > diff --git a/java/res/xml/kbd_qwerty_row1.xml b/java/res/xml/kbd_qwerty_row1.xml index e4356a8ad..d9249657e 100644 --- a/java/res/xml/kbd_qwerty_row1.xml +++ b/java/res/xml/kbd_qwerty_row1.xml @@ -28,53 +28,43 @@ diff --git a/java/res/xml/kbd_qwerty_row2.xml b/java/res/xml/kbd_qwerty_row2.xml index d5184954f..dd0035d93 100644 --- a/java/res/xml/kbd_qwerty_row2.xml +++ b/java/res/xml/kbd_qwerty_row2.xml @@ -28,22 +28,18 @@ latin:horizontalGap="5%p" /> @@ -53,7 +49,6 @@ latin:keyLabel="k" /> diff --git a/java/res/xml/kbd_qwerty_row3.xml b/java/res/xml/kbd_qwerty_row3.xml index 71a5f9c4a..26608fd71 100644 --- a/java/res/xml/kbd_qwerty_row3.xml +++ b/java/res/xml/kbd_qwerty_row3.xml @@ -30,23 +30,19 @@ latin:keyEdgeFlags="left" /> diff --git a/java/res/xml/kbd_qwerty_row4.xml b/java/res/xml/kbd_qwerty_row4.xml index cd03c51fc..0db011672 100644 --- a/java/res/xml/kbd_qwerty_row4.xml +++ b/java/res/xml/kbd_qwerty_row4.xml @@ -55,7 +55,8 @@ @@ -115,15 +101,12 @@ latin:keyLabel="k" /> diff --git a/java/res/xml/kbd_qwertz_rows.xml b/java/res/xml/kbd_qwertz_rows.xml index 4dbb6412a..375f12335 100644 --- a/java/res/xml/kbd_qwertz_rows.xml +++ b/java/res/xml/kbd_qwertz_rows.xml @@ -30,53 +30,43 @@ @@ -91,23 +81,19 @@ latin:keyEdgeFlags="left" /> diff --git a/java/res/xml/kbd_symbols.xml b/java/res/xml/kbd_symbols.xml index a7da01151..5d62deaa4 100644 --- a/java/res/xml/kbd_symbols.xml +++ b/java/res/xml/kbd_symbols.xml @@ -26,6 +26,8 @@ latin:keyWidth="10%p" latin:horizontalGap="@dimen/key_horizontal_gap" latin:verticalGap="@dimen/key_bottom_gap" + latin:popupKeyboardTemplate="@xml/kbd_popup_template" + latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column" > @@ -34,30 +36,24 @@ > + latin:popupCharacters="²,⅔" /> + latin:popupCharacters="³,¾,⅜" /> @@ -65,8 +61,7 @@ latin:keyLabel="9" /> @@ -77,34 +72,27 @@ latin:keyLabel="\#" /> + latin:popupCharacters="¢,£,€,¥,₣,₤,₱" /> + latin:popupCharacters="†,‡,★" /> + latin:popupCharacters="_,–,—" /> + latin:popupCharacters="[,{,<" /> @@ -114,16 +102,13 @@ latin:keyEdgeFlags="left" /> + latin:popupCharacters="“,”,«,»,˝" /> + latin:popupCharacters="‘,’" /> diff --git a/java/res/xml/kbd_symbols_row4.xml b/java/res/xml/kbd_symbols_row4.xml index 1a5417d08..b330095af 100644 --- a/java/res/xml/kbd_symbols_row4.xml +++ b/java/res/xml/kbd_symbols_row4.xml @@ -40,7 +40,8 @@ @@ -41,13 +43,11 @@ latin:keyLabel="|" /> + latin:popupCharacters="♪,♥,♠,♦,♣" /> @@ -73,14 +73,12 @@ latin:keyLabel="°" /> + latin:popupCharacters="↑,↓,←,→" /> + latin:popupCharacters="≠,≈,∞" /> + latin:popupCharacters="≤,«,‹" /> + latin:popupCharacters="≥,»,›" /> - - - - - - - - diff --git a/java/res/xml/popup_comma.xml b/java/res/xml/popup_comma.xml deleted file mode 100644 index 9ef49dfda..000000000 --- a/java/res/xml/popup_comma.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - diff --git a/java/res/xml/popup_domains.xml b/java/res/xml/popup_domains.xml deleted file mode 100644 index 9fbbdec11..000000000 --- a/java/res/xml/popup_domains.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/xml/popup_mic.xml b/java/res/xml/popup_mic.xml deleted file mode 100644 index 1851eba98..000000000 --- a/java/res/xml/popup_mic.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - diff --git a/java/res/xml/popup_punctuation.xml b/java/res/xml/popup_punctuation.xml deleted file mode 100644 index 6c778c724..000000000 --- a/java/res/xml/popup_punctuation.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java/res/xml/popup_slash.xml b/java/res/xml/popup_slash.xml deleted file mode 100644 index 611500c9e..000000000 --- a/java/res/xml/popup_slash.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - diff --git a/java/res/xml/popup_smileys.xml b/java/res/xml/popup_smileys.xml deleted file mode 100644 index b87667222..000000000 --- a/java/res/xml/popup_smileys.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index 47b3b4589..3b20298d2 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -34,7 +34,7 @@ android:key="popup_on" android:title="@string/popup_on_keypress" android:persistent="true" - android:defaultValue="@bool/default_popup_preview" + android:defaultValue="@bool/config_default_popup_preview" /> mStyles = new HashMap(); @@ -37,15 +39,15 @@ public class KeyStyles { public interface KeyStyle { public int[] getIntArray(TypedArray a, int index); + public CharSequence[] getTextArray(TypedArray a, int index); public Drawable getDrawable(TypedArray a, int index); public CharSequence getText(TypedArray a, int index); - public int getResourceId(TypedArray a, int index, int defaultValue); public int getInt(TypedArray a, int index, int defaultValue); public int getFlag(TypedArray a, int index, int defaultValue); public boolean getBoolean(TypedArray a, int index, boolean defaultValue); } - public static class EmptyKeyStyle implements KeyStyle { + /* package */ static class EmptyKeyStyle implements KeyStyle { private EmptyKeyStyle() { // Nothing to do. } @@ -55,6 +57,11 @@ public class KeyStyles { return parseIntArray(a, index); } + @Override + public CharSequence[] getTextArray(TypedArray a, int index) { + return parseTextArray(a, index); + } + @Override public Drawable getDrawable(TypedArray a, int index) { return a.getDrawable(index); @@ -65,11 +72,6 @@ public class KeyStyles { return a.getText(index); } - @Override - public int getResourceId(TypedArray a, int index, int defaultValue) { - return a.getResourceId(index, defaultValue); - } - @Override public int getInt(TypedArray a, int index, int defaultValue) { return a.getInt(index, defaultValue); @@ -85,19 +87,71 @@ public class KeyStyles { return a.getBoolean(index, defaultValue); } + protected static CharSequence[] parseTextArray(TypedArray a, int index) { + if (!a.hasValue(index)) + return null; + final CharSequence text = a.getText(index); + return parseCsvText(text); + } + + /* package */ static CharSequence[] parseCsvText(CharSequence text) { + final int size = text.length(); + if (size == 0) return null; + if (size == 1) return new CharSequence[] { text }; + final StringBuilder sb = new StringBuilder(); + ArrayList list = null; + int start = 0; + for (int pos = 0; pos < size; pos++) { + final char c = text.charAt(pos); + if (c == ',') { + if (list == null) list = new ArrayList(); + if (sb.length() == 0) { + list.add(text.subSequence(start, pos)); + } else { + list.add(sb.toString()); + sb.setLength(0); + } + start = pos + 1; + continue; + } else if (c == '\\') { + if (start == pos) { + // Skip escape character at the beginning of the value. + start++; + pos++; + } else { + if (start < pos && sb.length() == 0) + sb.append(text.subSequence(start, pos)); + pos++; + if (pos < size) + sb.append(text.charAt(pos)); + } + } else if (sb.length() > 0) { + sb.append(c); + } + } + if (list == null) { + return new CharSequence[] { sb.length() > 0 ? sb : text.subSequence(start, size) }; + } else { + list.add(sb.length() > 0 ? sb : text.subSequence(start, size)); + return list.toArray(new CharSequence[list.size()]); + } + } + protected static int[] parseIntArray(TypedArray a, int index) { + if (!a.hasValue(index)) + return null; TypedValue v = new TypedValue(); a.getValue(index, v); if (v.type == TypedValue.TYPE_INT_DEC || v.type == TypedValue.TYPE_INT_HEX) { return new int[] { v.data }; } else if (v.type == TypedValue.TYPE_STRING) { - return parseCSV(v.string.toString()); + return parseCsvInt(v.string.toString()); } else { return null; } } - private static int[] parseCSV(String value) { + /* package */ static int[] parseCsvInt(String value) { int count = 0; int lastIndex = 0; if (value.length() > 0) { @@ -110,17 +164,13 @@ public class KeyStyles { count = 0; StringTokenizer st = new StringTokenizer(value, ","); while (st.hasMoreTokens()) { - try { - values[count++] = Integer.parseInt(st.nextToken()); - } catch (NumberFormatException nfe) { - Log.w(TAG, "Error parsing integer CSV " + value); - } + values[count++] = Integer.parseInt(st.nextToken()); } return values; } } - public static class DeclaredKeyStyle extends EmptyKeyStyle { + private static class DeclaredKeyStyle extends EmptyKeyStyle { private final HashMap mAttributes = new HashMap(); @Override @@ -129,6 +179,12 @@ public class KeyStyles { ? super.getIntArray(a, index) : (int[])mAttributes.get(index); } + @Override + public CharSequence[] getTextArray(TypedArray a, int index) { + return a.hasValue(index) + ? super.getTextArray(a, index) : (CharSequence[])mAttributes.get(index); + } + @Override public Drawable getDrawable(TypedArray a, int index) { return a.hasValue(index) @@ -142,9 +198,9 @@ public class KeyStyles { } @Override - public int getResourceId(TypedArray a, int index, int defaultValue) { + public int getInt(TypedArray a, int index, int defaultValue) { final Integer value = (Integer)mAttributes.get(index); - return super.getResourceId(a, index, (value != null) ? value : defaultValue); + return super.getInt(a, index, (value != null) ? value : defaultValue); } @Override @@ -163,20 +219,21 @@ public class KeyStyles { super(); } - private void parseKeyStyleAttributes(TypedArray a) { + private void parseKeyStyleAttributes(TypedArray keyAttr) { // TODO: Currently not all Key attributes can be declared as style. - readIntArray(a, R.styleable.Keyboard_Key_codes); - readText(a, R.styleable.Keyboard_Key_keyLabel); - readFlag(a, R.styleable.Keyboard_Key_keyLabelOption); - readText(a, R.styleable.Keyboard_Key_keyOutputText); - readDrawable(a, R.styleable.Keyboard_Key_keyIcon); - readDrawable(a, R.styleable.Keyboard_Key_iconPreview); - readDrawable(a, R.styleable.Keyboard_Key_keyHintIcon); - readDrawable(a, R.styleable.Keyboard_Key_shiftedIcon); - readResourceId(a, R.styleable.Keyboard_Key_popupKeyboard); - readBoolean(a, R.styleable.Keyboard_Key_isModifier); - readBoolean(a, R.styleable.Keyboard_Key_isSticky); - readBoolean(a, R.styleable.Keyboard_Key_isRepeatable); + readIntArray(keyAttr, R.styleable.Keyboard_Key_codes); + readText(keyAttr, R.styleable.Keyboard_Key_keyLabel); + readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelOption); + readTextArray(keyAttr, R.styleable.Keyboard_Key_popupCharacters); + readInt(keyAttr, R.styleable.Keyboard_Key_maxPopupKeyboardColumn); + readText(keyAttr, R.styleable.Keyboard_Key_keyOutputText); + readDrawable(keyAttr, R.styleable.Keyboard_Key_keyIcon); + readDrawable(keyAttr, R.styleable.Keyboard_Key_iconPreview); + readDrawable(keyAttr, R.styleable.Keyboard_Key_keyHintIcon); + readDrawable(keyAttr, R.styleable.Keyboard_Key_shiftedIcon); + readBoolean(keyAttr, R.styleable.Keyboard_Key_isModifier); + readBoolean(keyAttr, R.styleable.Keyboard_Key_isSticky); + readBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable); } private void readDrawable(TypedArray a, int index) { @@ -189,9 +246,9 @@ public class KeyStyles { mAttributes.put(index, a.getText(index)); } - private void readResourceId(TypedArray a, int index) { + private void readInt(TypedArray a, int index) { if (a.hasValue(index)) - mAttributes.put(index, a.getResourceId(index, 0)); + mAttributes.put(index, a.getInt(index, 0)); } private void readFlag(TypedArray a, int index) { @@ -206,11 +263,15 @@ public class KeyStyles { } private void readIntArray(TypedArray a, int index) { - if (a.hasValue(index)) { - final int[] value = parseIntArray(a, index); - if (value != null) - mAttributes.put(index, value); - } + final int[] value = parseIntArray(a, index); + if (value != null) + mAttributes.put(index, value); + } + + private void readTextArray(TypedArray a, int index) { + final CharSequence[] value = parseTextArray(a, index); + if (value != null) + mAttributes.put(index, value); } private void addParent(DeclaredKeyStyle parentStyle) { @@ -218,15 +279,17 @@ public class KeyStyles { } } - public void parseKeyStyleAttributes(TypedArray a, TypedArray keyAttrs, + public void parseKeyStyleAttributes(TypedArray keyStyleAttr, TypedArray keyAttrs, XmlResourceParser parser) { - String styleName = a.getString(R.styleable.Keyboard_KeyStyle_styleName); + String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName); + if (DEBUG) Log.d(TAG, String.format("<%s styleName=%s />", + KeyboardParser.TAG_KEY_STYLE, styleName)); if (mStyles.containsKey(styleName)) throw new ParseException("duplicate key style declared: " + styleName, parser); final DeclaredKeyStyle style = new DeclaredKeyStyle(); - if (a.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) { - String parentStyle = a.getString( + if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) { + String parentStyle = keyStyleAttr.getString( R.styleable.Keyboard_KeyStyle_parentStyle); final DeclaredKeyStyle parent = mStyles.get(parentStyle); if (parent == null) diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 7641b4d7a..a20c86142 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -22,7 +22,6 @@ import org.xmlpull.v1.XmlPullParserException; import android.content.Context; import android.content.res.Resources; -import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.util.Log; @@ -92,6 +91,12 @@ public class Keyboard { /** Default gap between rows */ private int mDefaultVerticalGap; + /** Popup keyboard template */ + private int mPopupKeyboardResId; + + /** Maximum column for popup keyboard */ + private int mMaxPopupColumn; + /** List of shift keys in this keyboard and its icons and state */ private final List mShiftKeys = new ArrayList(); private final HashMap mShiftedIcons = new HashMap(); @@ -108,10 +113,10 @@ public class Keyboard { private int mTotalHeight; /** - * Total width of the keyboard, including left side gaps and keys, but not any gaps on the - * right side. + * Total width (minimum width) of the keyboard, including left side gaps and keys, but not any + * gaps on the right side. */ - private int mTotalWidth; + private int mMinWidth; /** List of keys in this keyboard */ private final List mKeys = new ArrayList(); @@ -144,27 +149,9 @@ public class Keyboard { * Creates a keyboard from the given xml key layout file. * @param context the application or service context * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. - */ - public Keyboard(Context context, int xmlLayoutResId) { - this(context, xmlLayoutResId, null); - } - - /** - * Creates a keyboard from the given keyboard identifier. - * @param context the application or service context * @param id keyboard identifier */ - public Keyboard(Context context, KeyboardId id) { - this(context, id.getXmlId(), id); - } - - /** - * Creates a keyboard from the given xml key layout file. - * @param context the application or service context - * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. - * @param id keyboard identifier - */ - private Keyboard(Context context, int xmlLayoutResId, KeyboardId id) { + public Keyboard(Context context, int xmlLayoutResId, KeyboardId id) { this(context, xmlLayoutResId, id, context.getResources().getDisplayMetrics().widthPixels, context.getResources().getDisplayMetrics().heightPixels); @@ -188,49 +175,6 @@ public class Keyboard { loadKeyboard(context, xmlLayoutResId); } - /** - *

Creates a blank keyboard from the given resource file and populates it with the specified - * characters in left-to-right, top-to-bottom fashion, using the specified number of columns. - *

- *

If the specified number of columns is -1, then the keyboard will fit as many keys as - * possible in each row.

- * @param context the application or service context - * @param layoutTemplateResId the layout template file, containing no keys. - * @param characters the list of characters to display on the keyboard. One key will be created - * for each character. - * @param columns the number of columns of keys to display. If this number is greater than the - * number of keys that can fit in a row, it will be ignored. If this number is -1, the - * keyboard will fit as many keys as possible in each row. - */ - public Keyboard(Context context, int layoutTemplateResId, - CharSequence characters, int columns, int horizontalPadding) { - this(context, layoutTemplateResId); - int x = 0; - int y = 0; - int column = 0; - mTotalWidth = 0; - - final Row row = new Row(this); - final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns; - for (int i = 0; i < characters.length(); i++) { - char c = characters.charAt(i); - if (column >= maxColumns - || x + mDefaultWidth + horizontalPadding > mDisplayWidth) { - x = 0; - y += mDefaultVerticalGap + mDefaultHeight; - column = 0; - } - final Key key = new Key(row, c, x, y); - column++; - x += key.mWidth + key.mGap; - mKeys.add(key); - if (x > mTotalWidth) { - mTotalWidth = x; - } - } - mTotalHeight = y + mDefaultHeight; - } - public List getKeys() { return mKeys; } @@ -277,8 +221,16 @@ public class Keyboard { return mTotalHeight; } + public void setHeight(int height) { + mTotalHeight = height; + } + public int getMinWidth() { - return mTotalWidth; + return mMinWidth; + } + + public void setMinWidth(int minWidth) { + mMinWidth = minWidth; } public int getDisplayHeight() { @@ -297,6 +249,22 @@ public class Keyboard { mKeyboardHeight = height; } + public int getPopupKeyboardResId() { + return mPopupKeyboardResId; + } + + public void setPopupKeyboardResId(int resId) { + mPopupKeyboardResId = resId; + } + + public int getMaxPopupKeyboardColumn() { + return mMaxPopupColumn; + } + + public void setMaxPopupKeyboardColumn(int column) { + mMaxPopupColumn = column; + } + public List getShiftKeys() { return mShiftKeys; } @@ -429,24 +397,12 @@ public class Keyboard { return EMPTY_INT_ARRAY; } - // TODO should be private - protected Row createRowFromXml(Resources res, XmlResourceParser parser) { - return new Row(res, this, parser); - } - - // TODO should be private - protected Key createKeyFromXml(Resources res, Row parent, int x, int y, - XmlResourceParser parser, KeyStyles keyStyles) { - return new Key(res, parent, x, y, parser, keyStyles); - } - private void loadKeyboard(Context context, int xmlLayoutResId) { try { - final Resources res = context.getResources(); - KeyboardParser parser = new KeyboardParser(this, res); - parser.parseKeyboard(res.getXml(xmlLayoutResId)); - // mTotalWidth is the width of this keyboard which is maximum width of row. - mTotalWidth = parser.getMaxRowWidth(); + KeyboardParser parser = new KeyboardParser(this, context.getResources()); + parser.parseKeyboard(xmlLayoutResId); + // mMinWidth is the width of this keyboard which is maximum width of row. + mMinWidth = parser.getMaxRowWidth(); mTotalHeight = parser.getTotalHeight(); } catch (XmlPullParserException e) { Log.w(TAG, "keyboard XML parse error: " + e); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index 883d2175c..f6577e747 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -46,12 +46,13 @@ public class KeyboardId { public final boolean mHasVoiceKey; public final int mImeOptions; public final boolean mEnableShiftLock; + public final String mXmlName; private final int mHashCode; - public KeyboardId(Locale locale, int orientation, int mode, - int xmlId, int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled, - boolean hasVoiceKey, int imeOptions, boolean enableShiftLock) { + public KeyboardId(String xmlName, int xmlId, Locale locale, int orientation, int mode, + int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled, boolean hasVoiceKey, + int imeOptions, boolean enableShiftLock) { this.mLocale = locale; this.mOrientation = orientation; this.mMode = mode; @@ -64,6 +65,7 @@ public class KeyboardId { this.mImeOptions = imeOptions & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION); this.mEnableShiftLock = enableShiftLock; + this.mXmlName = xmlName; this.mHashCode = Arrays.hashCode(new Object[] { locale, @@ -120,12 +122,12 @@ public class KeyboardId { @Override public String toString() { - return String.format("[%s %s %5s imeOptions=0x%08x xml=0x%08x %s%s%s%s%s]", + return String.format("[%s.xml %s %s %s imeOptions=%s %s%s%s%s%s]", + mXmlName, mLocale, (mOrientation == 1 ? "port" : "land"), modeName(mMode), - mImeOptions, - mXmlId, + imeOptionsName(mImeOptions), colorSchemeName(mColorScheme), (mHasSettingsKey ? " hasSettingsKey" : ""), (mVoiceKeyEnabled ? " voiceKeyEnabled" : ""), @@ -133,7 +135,7 @@ public class KeyboardId { (mEnableShiftLock ? " enableShiftLock" : "")); } - private static String modeName(int mode) { + public static String modeName(int mode) { switch (mode) { case MODE_TEXT: return "text"; case MODE_URL: return "url"; @@ -146,11 +148,33 @@ public class KeyboardId { return null; } - private static String colorSchemeName(int colorScheme) { + public static String colorSchemeName(int colorScheme) { switch (colorScheme) { case KeyboardView.COLOR_SCHEME_WHITE: return "white"; case KeyboardView.COLOR_SCHEME_BLACK: return "black"; } return null; } + + public static String imeOptionsName(int imeOptions) { + if (imeOptions == -1) return null; + final int actionNo = imeOptions & EditorInfo.IME_MASK_ACTION; + final String action; + switch (actionNo) { + case EditorInfo.IME_ACTION_UNSPECIFIED: action = "actionUnspecified"; break; + case EditorInfo.IME_ACTION_NONE: action = "actionNone"; break; + case EditorInfo.IME_ACTION_GO: action = "actionGo"; break; + case EditorInfo.IME_ACTION_SEARCH: action = "actionSearch"; break; + case EditorInfo.IME_ACTION_SEND: action = "actionSend"; break; + case EditorInfo.IME_ACTION_DONE: action = "actionDone"; break; + case EditorInfo.IME_ACTION_PREVIOUS: action = "actionPrevious"; break; + default: action = "actionUnknown(" + actionNo + ")"; break; + } + if ((imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { + return "flagNoEnterAction|" + action; + } else { + return action; + } + } } + diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java index 8a7d67451..ed59b8be5 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java @@ -30,6 +30,7 @@ import android.util.Xml; import android.view.InflateException; import java.io.IOException; +import java.util.Arrays; import java.util.List; /** @@ -103,7 +104,7 @@ import java.util.List; public class KeyboardParser { private static final String TAG = "KeyboardParser"; - private static final boolean DEBUG_TAG = false; + private static final boolean DEBUG = false; // Keyboard XML Tags private static final String TAG_KEYBOARD = "Keyboard"; @@ -115,7 +116,7 @@ public class KeyboardParser { private static final String TAG_SWITCH = "switch"; private static final String TAG_CASE = "case"; private static final String TAG_DEFAULT = "default"; - private static final String TAG_KEY_STYLE = "key-style"; + public static final String TAG_KEY_STYLE = "key-style"; private final Keyboard mKeyboard; private final Resources mResources; @@ -140,13 +141,13 @@ public class KeyboardParser { return mTotalHeight; } - public void parseKeyboard(XmlResourceParser parser) - throws XmlPullParserException, IOException { + public void parseKeyboard(int resId) throws XmlPullParserException, IOException { + if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mKeyboard.mId)); + final XmlResourceParser parser = mResources.getXml(resId); int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); - if (DEBUG_TAG) debugStartTag("parseKeyboard", tag, false); if (TAG_KEYBOARD.equals(tag)) { parseKeyboardAttributes(parser); parseKeyboardContent(parser, mKeyboard.getKeys()); @@ -160,28 +161,38 @@ public class KeyboardParser { private void parseKeyboardAttributes(XmlResourceParser parser) { final Keyboard keyboard = mKeyboard; - final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), + final TypedArray keyboardAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard); - final int displayHeight = keyboard.getDisplayHeight(); - final int keyboardHeight = (int)a.getDimension( - R.styleable.Keyboard_keyboardHeight, displayHeight / 2); - final int maxKeyboardHeight = getDimensionOrFraction(a, - R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); - // Keyboard height will not exceed maxKeyboardHeight. - final int height = Math.min(keyboardHeight, maxKeyboardHeight); - final int width = keyboard.getDisplayWidth(); + final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard_Key); + try { + final int displayHeight = keyboard.getDisplayHeight(); + final int keyboardHeight = (int)keyboardAttr.getDimension( + R.styleable.Keyboard_keyboardHeight, displayHeight / 2); + final int maxKeyboardHeight = getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); + // Keyboard height will not exceed maxKeyboardHeight. + final int height = Math.min(keyboardHeight, maxKeyboardHeight); + final int width = keyboard.getDisplayWidth(); - keyboard.setKeyboardHeight(height); - keyboard.setKeyWidth(getDimensionOrFraction(a, - R.styleable.Keyboard_keyWidth, width, width / 10)); - keyboard.setRowHeight(getDimensionOrFraction(a, - R.styleable.Keyboard_rowHeight, height, 50)); - keyboard.setHorizontalGap(getDimensionOrFraction(a, - R.styleable.Keyboard_horizontalGap, width, 0)); - keyboard.setVerticalGap(getDimensionOrFraction(a, - R.styleable.Keyboard_verticalGap, height, 0)); - a.recycle(); - if (DEBUG_TAG) Log.d(TAG, "id=" + keyboard.mId); + keyboard.setKeyboardHeight(height); + keyboard.setKeyWidth(getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_keyWidth, width, width / 10)); + keyboard.setRowHeight(getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_rowHeight, height, 50)); + keyboard.setHorizontalGap(getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_horizontalGap, width, 0)); + keyboard.setVerticalGap(getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_verticalGap, height, 0)); + keyboard.setPopupKeyboardResId(keyboardAttr.getResourceId( + R.styleable.Keyboard_popupKeyboardTemplate, 0)); + + keyboard.setMaxPopupKeyboardColumn(keyAttr.getInt( + R.styleable.Keyboard_Key_maxPopupKeyboardColumn, 5)); + } finally { + keyAttr.recycle(); + keyboardAttr.recycle(); + } } private void parseKeyboardContent(XmlResourceParser parser, List keys) @@ -190,9 +201,9 @@ public class KeyboardParser { while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); - if (DEBUG_TAG) debugStartTag("parseKeyboardContent", tag, keys == null); if (TAG_ROW.equals(tag)) { - Row row = mKeyboard.createRowFromXml(mResources, parser); + Row row = new Row(mResources, mKeyboard, parser); + if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW)); if (keys != null) startRow(row); parseRowContent(parser, row, keys); @@ -207,13 +218,12 @@ public class KeyboardParser { } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); - if (DEBUG_TAG) debugEndTag("parseKeyboardContent", tag, keys == null); if (TAG_KEYBOARD.equals(tag)) { endKeyboard(mKeyboard.getVerticalGap()); break; - } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)) { - break; - } else if (TAG_MERGE.equals(tag)) { + } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) + || TAG_MERGE.equals(tag)) { + if (DEBUG) Log.d(TAG, String.format("", tag)); break; } else if (TAG_KEY_STYLE.equals(tag)) { continue; @@ -230,7 +240,6 @@ public class KeyboardParser { while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); - if (DEBUG_TAG) debugStartTag("parseRowContent", tag, keys == null); if (TAG_KEY.equals(tag)) { parseKey(parser, row, keys); } else if (TAG_SPACER.equals(tag)) { @@ -246,14 +255,14 @@ public class KeyboardParser { } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); - if (DEBUG_TAG) debugEndTag("parseRowContent", tag, keys == null); if (TAG_ROW.equals(tag)) { + if (DEBUG) Log.d(TAG, String.format("", TAG_ROW)); if (keys != null) endRow(); break; - } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)) { - break; - } else if (TAG_MERGE.equals(tag)) { + } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) + || TAG_MERGE.equals(tag)) { + if (DEBUG) Log.d(TAG, String.format("", tag)); break; } else if (TAG_KEY_STYLE.equals(tag)) { continue; @@ -269,8 +278,10 @@ public class KeyboardParser { if (keys == null) { checkEndTag(TAG_KEY, parser); } else { - Key key = mKeyboard.createKeyFromXml(mResources, row, mCurrentX, mCurrentY, parser, - mKeyStyles); + Key key = new Key(mResources, row, mCurrentX, mCurrentY, parser, mKeyStyles); + if (DEBUG) Log.d(TAG, String.format("<%s keyLabel=%s codes=%s popupCharacters=%s />", + TAG_KEY, key.mLabel, Arrays.toString(key.mCodes), + Arrays.toString(key.mPopupCharacters))); checkEndTag(TAG_KEY, parser); keys.add(key); if (key.mCodes[0] == Keyboard.CODE_SHIFT) @@ -286,6 +297,7 @@ public class KeyboardParser { if (keys == null) { checkEndTag(TAG_SPACER, parser); } else { + if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER)); final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard); final int gap = getDimensionOrFraction(a, R.styleable.Keyboard_horizontalGap, @@ -320,7 +332,8 @@ public class KeyboardParser { checkEndTag(TAG_INCLUDE, parser); if (keyboardLayout == 0) throw new ParseException("No keyboardLayout attribute in ", parser); - if (DEBUG_TAG) Log.d(TAG, String.format(" keyboardLayout=0x%08x", keyboardLayout)); + if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />", + TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout))); parseMerge(mResources.getLayout(keyboardLayout), row, keys); } } @@ -331,7 +344,6 @@ public class KeyboardParser { while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); - if (DEBUG_TAG) debugStartTag("parseMerge", tag, keys == null); if (TAG_MERGE.equals(tag)) { if (row == null) { parseKeyboardContent(parser, keys); @@ -359,13 +371,12 @@ public class KeyboardParser { private void parseSwitchInternal(XmlResourceParser parser, Row row, List keys) throws XmlPullParserException, IOException { + if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mKeyboard.mId)); boolean selected = false; int event; - if (DEBUG_TAG) Log.d(TAG, "parseSwitchInternal: id=" + mKeyboard.mId); while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); - if (DEBUG_TAG) debugStartTag("parseSwitchInternal", tag, keys == null); if (TAG_CASE.equals(tag)) { selected |= parseCase(parser, row, selected ? null : keys); } else if (TAG_DEFAULT.equals(tag)) { @@ -375,8 +386,8 @@ public class KeyboardParser { } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); - if (DEBUG_TAG) debugEndTag("parseRowContent", tag, keys == null); if (TAG_SWITCH.equals(tag)) { + if (DEBUG) Log.d(TAG, String.format("", TAG_SWITCH)); break; } else { throw new IllegalEndTag(parser, TAG_KEY); @@ -426,20 +437,17 @@ public class KeyboardParser { final boolean selected = modeMatched && settingsKeyMatched && voiceEnabledMatched && voiceKeyMatched && colorSchemeMatched && imeOptionsMatched; - if (DEBUG_TAG) { - Log.d(TAG, String.format( - "parseCaseCondition: %s%s%s%s%s%s%s", - Boolean.toString(selected).toUpperCase(), - debugInteger(a, R.styleable.Keyboard_Case_mode, "mode"), - debugBoolean(a, R.styleable.Keyboard_Case_hasSettingsKey, - "hasSettingsKey"), - debugBoolean(a, R.styleable.Keyboard_Case_voiceKeyEnabled, - "voiceKeyEnabled"), - debugBoolean(a, R.styleable.Keyboard_Case_hasVoiceKey, "hasVoiceKey"), - debugInteger(viewAttr, R.styleable.KeyboardView_colorScheme, - "colorScheme"), - debugInteger(a, R.styleable.Keyboard_Case_imeOptions, "imeOptions"))); - } + if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s> %s", TAG_CASE, + textAttr(KeyboardId.modeName( + a.getInt(R.styleable.Keyboard_Case_mode, -1)), "mode"), + textAttr(KeyboardId.colorSchemeName( + a.getInt(R.styleable.KeyboardView_colorScheme, -1)), "colorSchemeName"), + booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"), + booleanAttr(a, R.styleable.Keyboard_Case_voiceKeyEnabled, "voiceKeyEnabled"), + booleanAttr(a, R.styleable.Keyboard_Case_hasVoiceKey, "hasVoiceKey"), + textAttr(KeyboardId.imeOptionsName( + a.getInt(R.styleable.Keyboard_Case_imeOptions, -1)), "imeOptions"), + Boolean.toString(selected))); return selected; } finally { @@ -462,6 +470,7 @@ public class KeyboardParser { private boolean parseDefault(XmlResourceParser parser, Row row, List keys) throws XmlPullParserException, IOException { + if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT)); if (row == null) { parseKeyboardContent(parser, keys); } else { @@ -471,18 +480,18 @@ public class KeyboardParser { } private void parseKeyStyle(XmlResourceParser parser, List keys) { - TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), + TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_KeyStyle); TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_Key); try { - if (!a.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) + if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) throw new ParseException("<" + TAG_KEY_STYLE + "/> needs styleName attribute", parser); if (keys != null) - mKeyStyles.parseKeyStyleAttributes(a, keyAttrs, parser); + mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); } finally { - a.recycle(); + keyStyleAttr.recycle(); keyAttrs.recycle(); } } @@ -561,19 +570,11 @@ public class KeyboardParser { } } - private static void debugStartTag(String title, String tag, boolean skip) { - Log.d(TAG, title + ": <" + tag + ">" + (skip ? " skip" : "")); + private static String textAttr(String value, String name) { + return value != null ? String.format(" %s=%s", name, value) : ""; } - private static void debugEndTag(String title, String tag, boolean skip) { - Log.d(TAG, title + ": " + (skip ? " skip" : "")); - } - - private static String debugInteger(TypedArray a, int index, String name) { - return a.hasValue(index) ? " " + name + "=" + a.getInt(index, 0) : ""; - } - - private static String debugBoolean(TypedArray a, int index, String name) { - return a.hasValue(index) ? " " + name + "=" + a.getBoolean(index, false) : ""; + 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/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index cd57db360..17d01f89f 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -115,7 +115,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private void makeSymbolsKeyboardIds() { final Locale locale = mSubtypeSwitcher.getInputLocale(); - final int orientation = mInputMethodService.getResources().getConfiguration().orientation; + final Resources res = mInputMethodService.getResources(); + final int orientation = res.getConfiguration().orientation; final int mode = mMode; final int colorScheme = getColorScheme(); final boolean hasSettingsKey = mHasSettingsKey; @@ -129,12 +130,14 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha // "more" and "locked more" key labels. To achieve these behavior, we should initialize // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard" // respectively here for xlarge device's layout switching. - mSymbolsId = new KeyboardId(locale, orientation, mode, - mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols, - colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true); - mSymbolsShiftedId = new KeyboardId(locale, orientation, mode, - mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift, - colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true); + int xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols; + mSymbolsId = new KeyboardId( + res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme, + hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true); + xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift; + mSymbolsShiftedId = new KeyboardId( + res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme, + hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true); } private boolean hasVoiceKey(boolean isSymbols) { @@ -230,9 +233,11 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha enableShiftLock = true; } } - final int orientation = mInputMethodService.getResources().getConfiguration().orientation; + final Resources res = mInputMethodService.getResources(); + final int orientation = res.getConfiguration().orientation; final Locale locale = mSubtypeSwitcher.getInputLocale(); - return new KeyboardId(locale, orientation, mode, xmlId, charColorId, + return new KeyboardId( + res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, charColorId, mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, imeOptions, enableShiftLock); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 4a3a58b94..2ad414c90 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -1000,7 +1000,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } // Set the preview background state mPreviewText.getBackground().setState( - key.mPopupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); + key.mPopupCharacters != null ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); popupPreviewX += mOffsetInWindow[0]; popupPreviewY += mOffsetInWindow[1]; @@ -1100,7 +1100,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } private View inflateMiniKeyboardContainer(Key popupKey) { - int popupKeyboardId = popupKey.mPopupResId; + int popupKeyboardResId = mKeyboard.getPopupKeyboardResId(); LayoutInflater inflater = (LayoutInflater)getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); View container = inflater.inflate(mPopupLayout, null); @@ -1157,13 +1157,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Remove gesture detector on mini-keyboard miniKeyboard.mGestureDetector = null; - Keyboard keyboard; - if (popupKey.mPopupCharacters != null) { - keyboard = new Keyboard(getContext(), popupKeyboardId, popupKey.mPopupCharacters, - -1, getPaddingLeft() + getPaddingRight()); - } else { - keyboard = new Keyboard(getContext(), popupKeyboardId); - } + Keyboard keyboard = new MiniKeyboardBuilder(getContext(), popupKeyboardResId, popupKey) + .build(); miniKeyboard.setKeyboard(keyboard); miniKeyboard.setPopupParent(this); @@ -1194,7 +1189,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { * method on the base class if the subclass doesn't wish to handle the call. */ protected boolean onLongPress(Key popupKey) { - if (popupKey.mPopupResId == 0) + if (popupKey.mPopupCharacters == null) return false; View container = mMiniKeyboardCache.get(popupKey); @@ -1272,15 +1267,14 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } private static boolean hasMultiplePopupChars(Key key) { - if (key.mPopupCharacters != null && key.mPopupCharacters.length() > 1) { + if (key.mPopupCharacters != null && key.mPopupCharacters.length > 1) { return true; } return false; } private static boolean isNumberAtLeftmostPopupChar(Key key) { - if (key.mPopupCharacters != null && key.mPopupCharacters.length() > 0 - && isAsciiDigit(key.mPopupCharacters.charAt(0))) { + if (key.mPopupCharacters != null && isAsciiDigit(key.mPopupCharacters[0].charAt(0))) { return true; } return false; diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java index 7cae4f1df..b9041e36b 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -44,15 +44,13 @@ public class LatinKeyboard extends Keyboard { public static final int OPACITY_FULLY_OPAQUE = 255; private static final int SPACE_LED_LENGTH_PERCENT = 80; - private Drawable mShiftLockPreviewIcon; - private Drawable mSpaceAutoCorrectionIndicator; + private final Drawable mSpaceAutoCorrectionIndicator; private final Drawable mButtonArrowLeftIcon; private final Drawable mButtonArrowRightIcon; private final int mSpaceBarTextShadowColor; private int mSpaceKeyIndex = -1; private int mSpaceDragStartX; private int mSpaceDragLastDiff; - private final Resources mRes; private final Context mContext; private boolean mCurrentlyInSpace; private SlidingLocaleDrawable mSlidingLocaleIcon; @@ -79,10 +77,9 @@ public class LatinKeyboard extends Keyboard { private static final String MEDIUM_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "medium"; public LatinKeyboard(Context context, KeyboardId id) { - super(context, id); + super(context, id.getXmlId(), id); final Resources res = context.getResources(); mContext = context; - mRes = res; if (id.mColorScheme == KeyboardView.COLOR_SCHEME_BLACK) { mSpaceBarTextShadowColor = res.getColor( R.color.latinkeyboard_bar_language_shadow_black); @@ -90,8 +87,6 @@ public class LatinKeyboard extends Keyboard { mSpaceBarTextShadowColor = res.getColor( R.color.latinkeyboard_bar_language_shadow_white); } - mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked); - setDefaultBounds(mShiftLockPreviewIcon); mSpaceAutoCorrectionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led); mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left); mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right); @@ -109,7 +104,7 @@ public class LatinKeyboard extends Keyboard { } private void updateSpaceBarForLocale(boolean isAutoCorrection) { - final Resources res = mRes; + final Resources res = mContext.getResources(); // If application locales are explicitly selected. if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) { mSpaceKey.setIcon(new BitmapDrawable(res, @@ -181,7 +176,7 @@ public class LatinKeyboard extends Keyboard { final int height = mSpaceIcon.getIntrinsicHeight(); final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(buffer); - final Resources res = mRes; + final Resources res = mContext.getResources(); canvas.drawColor(res.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR); SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance(); diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java new file mode 100644 index 000000000..1eb0c3f37 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * 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 java.util.List; + +public class MiniKeyboardBuilder { + private final Resources mRes; + private final Keyboard mKeyboard; + private final CharSequence[] mPopupCharacters; + private final int mMaxColumns; + private final int mNumRows; + private int mColPos; + private int mRowPos; + private Row mRow; + private int mX; + private int mY; + + public MiniKeyboardBuilder(Context context, int layoutTemplateResId, Key popupKey) { + mRes = context.getResources(); + mKeyboard = new Keyboard(context, layoutTemplateResId, null); + mPopupCharacters = popupKey.mPopupCharacters; + final int numKeys = mPopupCharacters.length; + final int maxColumns = popupKey.mMaxPopupColumn; + int numRows = numKeys / maxColumns; + if (numKeys % maxColumns != 0) numRows++; + mMaxColumns = maxColumns; + mNumRows = numRows; + // TODO: To determine key width we should pay attention to key label length. + mRow = new Row(mKeyboard, getRowFlags()); + if (numRows > 1) { + mColPos = numKeys % maxColumns; + if (mColPos > 0) mColPos = maxColumns - mColPos; + // Centering top-row keys. + mX = mColPos * (mRow.mDefaultWidth + mRow.mDefaultHorizontalGap) / 2; + } + mKeyboard.setMinWidth(0); + } + + public Keyboard build() { + List keys = mKeyboard.getKeys(); + for (CharSequence label : mPopupCharacters) { + refresh(); + final Key key = new Key(mRes, mRow, label, mX, mY); + keys.add(key); + advance(); + } + finish(); + return mKeyboard; + } + + private int getRowFlags() { + final int rowPos = mRowPos; + int rowFlags = 0; + if (rowPos == 0) rowFlags |= Keyboard.EDGE_TOP; + if (rowPos == mNumRows - 1) rowFlags |= Keyboard.EDGE_BOTTOM; + return rowFlags; + } + + private void refresh() { + if (mColPos >= mMaxColumns) { + final Row row = mRow; + // TODO: Allocate key position depending the precedence of popup characters. + mX = 0; + mY += row.mDefaultHeight + row.mVerticalGap; + mColPos = 0; + // TODO: To determine key width we should pay attention to key label length from + // bottom to up for rows. + mRow = new Row(mKeyboard, getRowFlags()); + mRowPos++; + } + } + + private void advance() { + final Row row = mRow; + final Keyboard keyboard = mKeyboard; + // TODO: Allocate key position depending the precedence of popup characters. + mX += row.mDefaultWidth + row.mDefaultHorizontalGap; + if (mX > keyboard.getMinWidth()) + keyboard.setMinWidth(mX); + mColPos++; + } + + private void finish() { + mKeyboard.setHeight(mY + mRow.mDefaultHeight); + } +} \ No newline at end of file diff --git a/java/src/com/android/inputmethod/keyboard/PopupCharactersParser.java b/java/src/com/android/inputmethod/keyboard/PopupCharactersParser.java new file mode 100644 index 000000000..cad3da03e --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/PopupCharactersParser.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * 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 com.android.inputmethod.latin.R; + +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; + +/** + * String parser of popupCharacters attribute of Key. + * The string is comma separated texts each of which represents one popup key. + * Each popup key text is one of the following: + * - A single letter (Letter) + * - Label optionally followed by keyOutputText or code (keyLabel|keyOutputText). + * - Icon followed by keyOutputText or code (@drawable/icon|@integer/key_code) + * Special character, comma ',' backslash '\', and bar '|' can be escaped by '\' + * character. + * Note that the character '@' and '\' are also parsed by XML parser and CSV parser as well. + */ +public class PopupCharactersParser { + private static final char ESCAPE = '\\'; + private static final String LABEL_END = "|"; + private static final String PREFIX_AT = "@"; + private static final String PREFIX_ICON = PREFIX_AT + "drawable/"; + private static final String PREFIX_CODE = PREFIX_AT + "integer/"; + private static final int[] DUMMY_CODES = { 0 }; + + private PopupCharactersParser() { + // Intentional empty constructor for utility class. + } + + private static boolean hasIcon(String popupSpec) { + if (popupSpec.startsWith(PREFIX_ICON)) { + final int end = indexOfLabelEnd(popupSpec, 0); + if (end > 0) + return true; + throw new PopupCharactersParserError("outputText or code not specified: " + popupSpec); + } + return false; + } + + private static boolean hasCode(String popupSpec) { + final int end = indexOfLabelEnd(popupSpec, 0); + if (end > 0 && end + 1 < popupSpec.length() + && popupSpec.substring(end + 1).startsWith(PREFIX_CODE)) { + return true; + } + return false; + } + + private static String parseEscape(String text) { + if (text.indexOf(ESCAPE) < 0) + return text; + final int length = text.length(); + final StringBuilder sb = new StringBuilder(); + for (int pos = 0; pos < length; pos++) { + final char c = text.charAt(pos); + if (c == ESCAPE && pos + 1 < length) { + sb.append(text.charAt(++pos)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + private static int indexOfLabelEnd(String popupSpec, int start) { + if (popupSpec.indexOf(ESCAPE, start) < 0) { + final int end = popupSpec.indexOf(LABEL_END, start); + if (end == 0) + throw new PopupCharactersParserError(LABEL_END + " at " + start + ": " + popupSpec); + return end; + } + final int length = popupSpec.length(); + for (int pos = start; pos < length; pos++) { + final char c = popupSpec.charAt(pos); + if (c == ESCAPE && pos + 1 < length) { + pos++; + } else if (popupSpec.startsWith(LABEL_END, pos)) { + return pos; + } + } + return -1; + } + + public static String getLabel(String popupSpec) { + if (hasIcon(popupSpec)) + return null; + final int end = indexOfLabelEnd(popupSpec, 0); + final String label = (end > 0) ? parseEscape(popupSpec.substring(0, end)) + : parseEscape(popupSpec); + if (TextUtils.isEmpty(label)) + throw new PopupCharactersParserError("Empty label: " + popupSpec); + return label; + } + + public static String getOutputText(String popupSpec) { + if (hasCode(popupSpec)) + return null; + final int end = indexOfLabelEnd(popupSpec, 0); + if (end > 0) { + if (indexOfLabelEnd(popupSpec, end + 1) >= 0) + throw new PopupCharactersParserError("Multiple " + LABEL_END + ": " + + popupSpec); + final String outputText = parseEscape(popupSpec.substring(end + LABEL_END.length())); + if (!TextUtils.isEmpty(outputText)) + return outputText; + throw new PopupCharactersParserError("Empty outputText: " + popupSpec); + } + final String label = getLabel(popupSpec); + if (label == null) + throw new PopupCharactersParserError("Empty label: " + popupSpec); + // Code is automatically generated for one letter label. See getCode(). + if (label.length() == 1) + return null; + return label; + } + + public static int[] getCodes(Resources res, String popupSpec) { + if (hasCode(popupSpec)) { + final int end = indexOfLabelEnd(popupSpec, 0); + if (indexOfLabelEnd(popupSpec, end + 1) >= 0) + throw new PopupCharactersParserError("Multiple " + LABEL_END + ": " + popupSpec); + final int resId = getResourceId(res, + popupSpec.substring(end + LABEL_END.length() + PREFIX_AT.length())); + final int code = res.getInteger(resId); + return new int[] { code }; + } + if (indexOfLabelEnd(popupSpec, 0) > 0) + return DUMMY_CODES; + final String label = getLabel(popupSpec); + // Code is automatically generated for one letter label. + if (label != null && label.length() == 1) + return new int[] { label.charAt(0) }; + return DUMMY_CODES; + } + + public static Drawable getIcon(Resources res, String popupSpec) { + if (hasIcon(popupSpec)) { + int end = popupSpec.indexOf(LABEL_END, PREFIX_ICON.length() + 1); + int resId = getResourceId(res, popupSpec.substring(PREFIX_AT.length(), end)); + return res.getDrawable(resId); + } + return null; + } + + private static int getResourceId(Resources res, String name) { + String packageName = res.getResourcePackageName(R.string.english_ime_name); + int resId = res.getIdentifier(name, null, packageName); + if (resId == 0) + throw new PopupCharactersParserError("Unknown resource: " + name); + return resId; + } + + @SuppressWarnings("serial") + public static class PopupCharactersParserError extends RuntimeException { + public PopupCharactersParserError(String message) { + super(message); + } + } +} diff --git a/java/src/com/android/inputmethod/keyboard/Row.java b/java/src/com/android/inputmethod/keyboard/Row.java index 7c158bca0..198f02ca8 100644 --- a/java/src/com/android/inputmethod/keyboard/Row.java +++ b/java/src/com/android/inputmethod/keyboard/Row.java @@ -45,13 +45,13 @@ public class Row { private final Keyboard mKeyboard; - public Row(Keyboard keyboard) { + public Row(Keyboard keyboard, int rowFlags) { this.mKeyboard = keyboard; mDefaultHeight = keyboard.getRowHeight(); mDefaultWidth = keyboard.getKeyWidth(); mDefaultHorizontalGap = keyboard.getHorizontalGap(); mVerticalGap = keyboard.getVerticalGap(); - mRowEdgeFlags = Keyboard.EDGE_TOP | Keyboard.EDGE_BOTTOM; + mRowEdgeFlags = rowFlags; } public Row(Resources res, Keyboard keyboard, XmlResourceParser parser) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 243306a35..12a24e87a 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2039,7 +2039,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen && prefs.getBoolean(Settings.PREF_VIBRATE_ON, false); mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, false); mPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON, - mResources.getBoolean(R.bool.default_popup_preview)); + mResources.getBoolean(R.bool.config_default_popup_preview)); mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true); diff --git a/tests/src/com/android/inputmethod/keyboard/KeyStylesTests.java b/tests/src/com/android/inputmethod/keyboard/KeyStylesTests.java new file mode 100644 index 000000000..3f2b7f4d5 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/KeyStylesTests.java @@ -0,0 +1,120 @@ +/* + * 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; + +import com.android.inputmethod.keyboard.KeyStyles.EmptyKeyStyle; + +import android.test.AndroidTestCase; +import android.text.TextUtils; + +public class KeyStylesTests extends AndroidTestCase { + private static void assertNumberFormatException(String message, String value) { + try { + EmptyKeyStyle.parseCsvInt(value); + fail(message); + } catch (NumberFormatException nfe) { + // success. + } + } + + private static void assertIntArray(String message, String value, Integer ... expected) { + final int actual[] = EmptyKeyStyle.parseCsvInt(value); + assertSame(message + ": result length", expected.length, actual.length); + for (int i = 0; i < actual.length; i++) { + assertEquals(message + ": result at " + i + ":", (int)expected[i], actual[i]); + } + } + + private static String format(String message, Object expected, Object actual) { + return message + " expected:<" + expected + "> but was:<" + actual + ">"; + } + + private static void assertTextArray(String message, CharSequence value, + CharSequence ... expected) { + final CharSequence actual[] = EmptyKeyStyle.parseCsvText(value); + if (expected.length == 0) { + assertNull(message, actual); + return; + } + assertSame(message + ": result length", expected.length, actual.length); + for (int i = 0; i < actual.length; i++) { + final boolean equals = TextUtils.equals(expected[i], actual[i]); + assertTrue(format(message + ": result at " + i + ":", expected[i], actual[i]), equals); + } + } + + public void testParseCsvInt() { + assertIntArray("Empty string", ""); + assertNumberFormatException("Spaces", " "); + assertNumberFormatException("Non-decimal number", "abc"); + assertIntArray("Single number", "123", 123); + assertIntArray("Negative number", "-123", -123); + assertNumberFormatException("Hexadecimal number", "1b2b"); + assertIntArray("Multiple numbers", "123,456", 123, 456); + assertNumberFormatException("Non-decimal numbers", "123,abc"); + assertNumberFormatException("Escaped comma", "123\\,456"); + assertNumberFormatException("Escaped escape", "123\\\\,456"); + } + + public void testParseCsvTextZero() { + assertTextArray("Empty string", ""); + } + + public void testParseCsvTextSingle() { + assertTextArray("Single char", "a", "a"); + assertTextArray("Space", " ", " "); + assertTextArray("Single label", "abc", "abc"); + assertTextArray("Spaces", " ", " "); + assertTextArray("Spaces in label", "a b c", "a b c"); + assertTextArray("Spaces at beginning of label", " abc", " abc"); + assertTextArray("Spaces at end of label", "abc ", "abc "); + assertTextArray("label surrounded by spaces", " abc ", " abc "); + } + + public void testParseCsvTextSingleEscaped() { + assertTextArray("Escaped char", "\\a", "a"); + assertTextArray("Escaped comma", "\\,", ","); + assertTextArray("Escaped escape", "\\\\", "\\"); + assertTextArray("Escaped label", "a\\bc", "abc"); + assertTextArray("Escaped label at begininng", "\\abc", "abc"); + assertTextArray("Escaped label with comma", "a\\,c", "a,c"); + assertTextArray("Escaped label with comma at beginning", "\\,bc", ",bc"); + assertTextArray("Escaped label with successive", "\\,\\\\bc", ",\\bc"); + assertTextArray("Escaped label with escape", "a\\\\c", "a\\c"); + } + + public void testParseCsvTextMulti() { + assertTextArray("Multiple chars", "a,b,c", "a", "b", "c"); + assertTextArray("Multiple chars surrounded by spaces", " a , b , c ", " a ", " b ", " c "); + assertTextArray("Multiple labels", "abc,def,ghi", "abc", "def", "ghi"); + assertTextArray("Multiple labels surrounded by spaces", " abc , def , ghi ", + " abc ", " def ", " ghi "); + } + + public void testParseCsvTextMultiEscaped() { + assertTextArray("Multiple chars with comma", "a,\\,,c", "a", ",", "c"); + assertTextArray("Multiple chars with comma surrounded by spaces", " a , \\, , c ", + " a ", " , ", " c "); + assertTextArray("Multiple labels with escape", "\\abc,d\\ef,gh\\i", "abc", "def", "ghi"); + assertTextArray("Multiple labels with escape surrounded by spaces", + " \\abc , d\\ef , gh\\i ", " abc ", " def ", " ghi "); + assertTextArray("Multiple labels with comma and escape", + "ab\\\\,d\\\\\\,,g\\,i", "ab\\", "d\\,", "g,i"); + assertTextArray("Multiple labels with comma and escape surrounded by spaces", + " ab\\\\ , d\\\\\\, , g\\,i ", " ab\\ ", " d\\, ", " g,i "); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/PopupCharactersParserTests.java b/tests/src/com/android/inputmethod/keyboard/PopupCharactersParserTests.java new file mode 100644 index 000000000..77b62ca5d --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/PopupCharactersParserTests.java @@ -0,0 +1,205 @@ +/* + * 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; + +import com.android.inputmethod.latin.R; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.test.AndroidTestCase; + +public class PopupCharactersParserTests extends AndroidTestCase { + private Resources mRes; + + private static final String CODE_SETTINGS = "@integer/key_settings"; + private static final String ICON_SETTINGS = "@drawable/sym_keyboard_settings"; + private static final String CODE_NON_EXISTING = "@integer/non_existing"; + private static final String ICON_NON_EXISTING = "@drawable/non_existing"; + + private int mCodeSettings; + private Drawable mIconSettings; + + private static final Integer[] DUMMY_CODES = { 0 }; + + @Override + protected void setUp() { + Resources res = getContext().getResources(); + mRes = res; + + final String packageName = res.getResourcePackageName(R.string.english_ime_name); + final int codeId = res.getIdentifier(CODE_SETTINGS.substring(1), null, packageName); + final int iconId = res.getIdentifier(ICON_SETTINGS.substring(1), null, packageName); + mCodeSettings = res.getInteger(codeId); + mIconSettings = res.getDrawable(iconId); + } + + private void assertParser(String message, String popupSpec, String expectedLabel, + String expectedOutputText, Drawable expectedIcon, Integer ... expectedCodes) { + String actualLabel = PopupCharactersParser.getLabel(popupSpec); + assertEquals(message + ": label:", expectedLabel, actualLabel); + + String actualOutputText = PopupCharactersParser.getOutputText(popupSpec); + assertEquals(message + ": ouptputText:", expectedOutputText, actualOutputText); + + Drawable actualIcon = PopupCharactersParser.getIcon(mRes, popupSpec); + // We can not compare drawables, checking null or non-null instead. + if (expectedIcon == null) { + assertNull(message + ": icon null:", actualIcon); + } else { + assertNotNull(message + ": icon non-null:", actualIcon); + } + + int[] actualCodes = PopupCharactersParser.getCodes(mRes, popupSpec); + if (expectedCodes == null) { + assertNull(message + ": codes null:", actualCodes); + return; + } + assertSame(message + ": codes length:", expectedCodes.length, actualCodes.length); + for (int i = 0; i < actualCodes.length; i++) { + assertEquals(message + ": codes value at " + i + ":", (int)expectedCodes[i], + actualCodes[i]); + } + } + + private void assertParserError(String message, String popupSpec, String expectedLabel, + String expectedOutputText, Drawable expectedIcon, Integer ... expectedCodes) { + try { + if (expectedCodes.length > 0) { + assertParser(message, popupSpec, expectedLabel, expectedOutputText, expectedIcon, + expectedCodes); + } else { + assertParser(message, popupSpec, expectedLabel, expectedOutputText, expectedIcon, + DUMMY_CODES); + } + fail(message); + } catch (PopupCharactersParser.PopupCharactersParserError pcpe) { + // success. + } + } + + public void testSingleLetter() { + assertParser("Single letter", "a", "a", null, null, (int)'a'); + assertParser("Single escaped bar", "\\|", "|", null, null, (int)'|'); + assertParser("Single escaped escape", "\\\\", "\\", null, null, (int)'\\'); + assertParser("Single comma", ",", ",", null, null, (int)','); + assertParser("Single escaped comma", "\\,", ",", null, null, (int)','); + assertParser("Single escaped letter", "\\a", "a", null, null, (int)'a'); + assertParser("Single at", "@", "@", null, null, (int)'@'); + assertParser("Single escaped at", "\\@", "@", null, null, (int)'@'); + assertParser("Single letter with outputText", "a|abc", "a", "abc", null, DUMMY_CODES); + assertParser("Single letter with escaped outputText", "a|a\\|c", "a", "a|c", null, + DUMMY_CODES); + assertParser("Single letter with comma outputText", "a|a,b", "a", "a,b", null, DUMMY_CODES); + assertParser("Single letter with escaped comma outputText", "a|a\\,b", "a", "a,b", null, + DUMMY_CODES); + assertParser("Single letter with outputText starts with at", "a|@bc", "a", "@bc", null, + DUMMY_CODES); + assertParser("Single letter with outputText contains at", "a|a@c", "a", "a@c", null, + DUMMY_CODES); + assertParser("Single letter with escaped at outputText", "a|\\@bc", "a", "@bc", null, + DUMMY_CODES); + assertParser("Single escaped escape with outputText", "\\\\|\\\\", "\\", "\\", null, + DUMMY_CODES); + assertParser("Single escaped bar with outputText", "\\||\\|", "|", "|", null, DUMMY_CODES); + assertParser("Single letter with code", "a|" + CODE_SETTINGS, "a", null, null, + mCodeSettings); + } + + public void testLabel() { + assertParser("Simple label", "abc", "abc", "abc", null, DUMMY_CODES); + assertParser("Label with escaped bar", "a\\|c", "a|c", "a|c", null, DUMMY_CODES); + assertParser("Label with escaped escape", "a\\\\c", "a\\c", "a\\c", null, DUMMY_CODES); + assertParser("Label with comma", "a,c", "a,c", "a,c", null, DUMMY_CODES); + assertParser("Label with escaped comma", "a\\,c", "a,c", "a,c", null, DUMMY_CODES); + assertParser("Label starts with at", "@bc", "@bc", "@bc", null, DUMMY_CODES); + assertParser("Label contains at", "a@c", "a@c", "a@c", null, DUMMY_CODES); + assertParser("Label with escaped at", "\\@bc", "@bc", "@bc", null, DUMMY_CODES); + assertParser("Label with escaped letter", "\\abc", "abc", "abc", null, DUMMY_CODES); + assertParser("Label with outputText", "abc|def", "abc", "def", null, DUMMY_CODES); + assertParser("Label with comma and outputText", "a,c|def", "a,c", "def", null, DUMMY_CODES); + assertParser("Escaped comma label with outputText", "a\\,c|def", "a,c", "def", null, + DUMMY_CODES); + assertParser("Escaped label with outputText", "a\\|c|def", "a|c", "def", null, DUMMY_CODES); + assertParser("Label with escaped bar outputText", "abc|d\\|f", "abc", "d|f", null, + DUMMY_CODES); + assertParser("Escaped escape label with outputText", "a\\\\|def", "a\\", "def", null, + DUMMY_CODES); + assertParser("Label starts with at and outputText", "@bc|def", "@bc", "def", null, + DUMMY_CODES); + assertParser("Label contains at label and outputText", "a@c|def", "a@c", "def", null, + DUMMY_CODES); + assertParser("Escaped at label with outputText", "\\@bc|def", "@bc", "def", null, + DUMMY_CODES); + assertParser("Label with comma outputText", "abc|a,b", "abc", "a,b", null, DUMMY_CODES); + assertParser("Label with escaped comma outputText", "abc|a\\,b", "abc", "a,b", null, + DUMMY_CODES); + assertParser("Label with outputText starts with at", "abc|@bc", "abc", "@bc", null, + DUMMY_CODES); + assertParser("Label with outputText contains at", "abc|a@c", "abc", "a@c", null, + DUMMY_CODES); + assertParser("Label with escaped at outputText", "abc|\\@bc", "abc", "@bc", null, + DUMMY_CODES); + assertParser("Label with escaped bar outputText", "abc|d\\|f", "abc", "d|f", + null, DUMMY_CODES); + assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", "a|c", "d|f", + null, DUMMY_CODES); + assertParser("Label with code", "abc|" + CODE_SETTINGS, "abc", null, null, mCodeSettings); + assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS, "a|c", null, null, + mCodeSettings); + } + + public void testIconAndCode() { + assertParser("Icon with outputText", ICON_SETTINGS + "|abc", null, "abc", mIconSettings, + DUMMY_CODES); + assertParser("Icon with outputText starts with at", ICON_SETTINGS + "|@bc", null, "@bc", + mIconSettings, DUMMY_CODES); + assertParser("Icon with outputText contains at", ICON_SETTINGS + "|a@c", null, "a@c", + mIconSettings, DUMMY_CODES); + assertParser("Icon with escaped at outputText", ICON_SETTINGS + "|\\@bc", null, "@bc", + mIconSettings, DUMMY_CODES); + assertParser("Label starts with at and code", "@bc|" + CODE_SETTINGS, "@bc", null, null, + mCodeSettings); + assertParser("Label contains at and code", "a@c|" + CODE_SETTINGS, "a@c", null, null, + mCodeSettings); + assertParser("Escaped at label with code", "\\@bc|" + CODE_SETTINGS, "@bc", null, null, + mCodeSettings); + assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS, null, null, + mIconSettings, mCodeSettings); + } + + public void testFormatError() { + assertParserError("Empty spec", "", null, null, null); + assertParserError("Empty label with outputText", "|a", null, "a", null); + assertParserError("Empty label with code", "|" + CODE_SETTINGS, null, null, null, + mCodeSettings); + assertParserError("Empty outputText with label", "a|", "a", null, null); + assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", null, null, + mIconSettings); + assertParserError("Empty icon and code", "|", null, null, null); + assertParserError("Icon without code", ICON_SETTINGS, null, null, mIconSettings); + assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc", null, "abc", null); + assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, "abc", null, null); + assertParserError("Third bar at end", "a|b|", "a", null, null); + assertParserError("Multiple bar", "a|b|c", "a", null, null); + assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c", "a", + null, null, mCodeSettings); + assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c", null, + null, mIconSettings); + assertParserError("Multiple bar with icon and code", + ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", null, null, mIconSettings, + mCodeSettings); + } +}