Make KeySpecParser case insensitive

Change-Id: I76c3e9179dd8777d3cf3138ad76513d83672debf
main
Tadashi G. Takaoka 2012-04-20 04:35:04 +09:00
parent 9d9b44dc67
commit 2f16fd40fa
15 changed files with 468 additions and 264 deletions

View File

@ -98,7 +98,6 @@
latin:code="!code/key_shortcut" latin:code="!code/key_shortcut"
latin:keyIcon="iconShortcutKey" latin:keyIcon="iconShortcutKey"
latin:keyIconDisabled="iconDisabledShortcutKey" latin:keyIconDisabled="iconDisabledShortcutKey"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style
@ -132,7 +131,6 @@
latin:styleName="toSymbolKeyStyle" latin:styleName="toSymbolKeyStyle"
latin:code="!code/key_switch_alpha_symbol" latin:code="!code/key_switch_alpha_symbol"
latin:keyLabel="!label/label_to_symbol_key" latin:keyLabel="!label/label_to_symbol_key"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style
@ -146,14 +144,12 @@
latin:styleName="toMoreSymbolKeyStyle" latin:styleName="toMoreSymbolKeyStyle"
latin:code="!code/key_shift" latin:code="!code/key_shift"
latin:keyLabel="!label/label_to_more_symbol_for_tablet_key" latin:keyLabel="!label/label_to_more_symbol_for_tablet_key"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style
latin:styleName="backFromMoreSymbolKeyStyle" latin:styleName="backFromMoreSymbolKeyStyle"
latin:code="!code/key_shift" latin:code="!code/key_shift"
latin:keyLabel="!label/label_to_symbol_key" latin:keyLabel="!label/label_to_symbol_key"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style

View File

@ -97,7 +97,6 @@
latin:code="!code/key_shortcut" latin:code="!code/key_shortcut"
latin:keyIcon="iconShortcutKey" latin:keyIcon="iconShortcutKey"
latin:keyIconDisabled="iconDisabledShortcutKey" latin:keyIconDisabled="iconDisabledShortcutKey"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style
@ -131,7 +130,7 @@
latin:styleName="toSymbolKeyStyle" latin:styleName="toSymbolKeyStyle"
latin:code="!code/key_switch_alpha_symbol" latin:code="!code/key_switch_alpha_symbol"
latin:keyLabel="!label/label_to_symbol_key" latin:keyLabel="!label/label_to_symbol_key"
latin:keyLabelFlags="fontNormal|preserveCase" latin:keyLabelFlags="fontNormal"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style
@ -145,14 +144,14 @@
latin:styleName="toMoreSymbolKeyStyle" latin:styleName="toMoreSymbolKeyStyle"
latin:code="!code/key_shift" latin:code="!code/key_shift"
latin:keyLabel="!label/label_to_more_symbol_for_tablet_key" latin:keyLabel="!label/label_to_more_symbol_for_tablet_key"
latin:keyLabelFlags="fontNormal|preserveCase" latin:keyLabelFlags="fontNormal"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style
latin:styleName="backFromMoreSymbolKeyStyle" latin:styleName="backFromMoreSymbolKeyStyle"
latin:code="!code/key_shift" latin:code="!code/key_shift"
latin:keyLabel="!label/label_to_symbol_key" latin:keyLabel="!label/label_to_symbol_key"
latin:keyLabelFlags="fontNormal|preserveCase" latin:keyLabelFlags="fontNormal"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style

View File

@ -34,7 +34,7 @@
<default> <default>
<key-style <key-style
latin:styleName="f1MoreKeysStyle" latin:styleName="f1MoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint"
latin:moreKeys="!label/settings_as_more_key" latin:moreKeys="!label/settings_as_more_key"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
</default> </default>
@ -122,7 +122,6 @@
latin:code="!code/key_shortcut" latin:code="!code/key_shortcut"
latin:keyIcon="iconShortcutKey" latin:keyIcon="iconShortcutKey"
latin:keyIconDisabled="iconDisabledShortcutKey" latin:keyIconDisabled="iconDisabledShortcutKey"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
latin:altCode="!code/key_space" latin:altCode="!code/key_space"
latin:parentStyle="f1MoreKeysStyle" /> latin:parentStyle="f1MoreKeysStyle" />
@ -159,7 +158,7 @@
latin:code="!code/key_switch_alpha_symbol" latin:code="!code/key_switch_alpha_symbol"
latin:keyIcon="iconShortcutForLabel" latin:keyIcon="iconShortcutForLabel"
latin:keyLabel="!label/label_to_symbol_with_microphone_key" latin:keyLabel="!label/label_to_symbol_with_microphone_key"
latin:keyLabelFlags="withIconRight|preserveCase" latin:keyLabelFlags="withIconRight"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
</case> </case>
@ -168,7 +167,6 @@
latin:styleName="toSymbolKeyStyle" latin:styleName="toSymbolKeyStyle"
latin:code="!code/key_switch_alpha_symbol" latin:code="!code/key_switch_alpha_symbol"
latin:keyLabel="!label/label_to_symbol_key" latin:keyLabel="!label/label_to_symbol_key"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
</default> </default>
@ -184,21 +182,19 @@
latin:styleName="toMoreSymbolKeyStyle" latin:styleName="toMoreSymbolKeyStyle"
latin:code="!code/key_shift" latin:code="!code/key_shift"
latin:keyLabel="!label/label_to_more_symbol_key" latin:keyLabel="!label/label_to_more_symbol_key"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style
latin:styleName="backFromMoreSymbolKeyStyle" latin:styleName="backFromMoreSymbolKeyStyle"
latin:code="!code/key_shift" latin:code="!code/key_shift"
latin:keyLabel="!label/label_to_symbol_key" latin:keyLabel="!label/label_to_symbol_key"
latin:keyLabelFlags="preserveCase"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
<key-style <key-style
latin:styleName="punctuationKeyStyle" latin:styleName="punctuationKeyStyle"
latin:keyLabel="." latin:keyLabel="."
latin:keyHintLabel="!label/keyhintlabel_for_punctuation" latin:keyHintLabel="!label/keyhintlabel_for_punctuation"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint"
latin:moreKeys="!label/more_keys_for_punctuation" latin:moreKeys="!label/more_keys_for_punctuation"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
</merge> </merge>

View File

@ -94,7 +94,7 @@
latin:styleName="defaultEnterKeyStyle" latin:styleName="defaultEnterKeyStyle"
latin:code="!code/key_enter" latin:code="!code/key_enter"
latin:keyIcon="iconReturnKey" latin:keyIcon="iconReturnKey"
latin:keyLabelFlags="autoXScale|preserveCase|followKeyLabelRatio" latin:keyLabelFlags="autoXScale|followKeyLabelRatio"
latin:keyActionFlags="noKeyPreview" latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" latin:backgroundType="functional"
latin:parentStyle="navigateMoreKeysStyle" /> latin:parentStyle="navigateMoreKeysStyle" />

View File

@ -27,55 +27,45 @@
> >
<Key <Key
latin:keyLabel="Q" latin:keyLabel="Q"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="1" latin:keyHintLabel="1"
latin:additionalMoreKeys="1" /> latin:additionalMoreKeys="1" />
<!-- U+10ED: "ჭ" GEORGIAN LETTER CHAR --> <!-- U+10ED: "ჭ" GEORGIAN LETTER CHAR -->
<Key <Key
latin:keyLabel="&#x10ED;" latin:keyLabel="&#x10ED;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="2" latin:keyHintLabel="2"
latin:additionalMoreKeys="2" /> latin:additionalMoreKeys="2" />
<Key <Key
latin:keyLabel="E" latin:keyLabel="E"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="3" latin:keyHintLabel="3"
latin:additionalMoreKeys="3" /> latin:additionalMoreKeys="3" />
<!-- U+10E6: "ღ" GEORGIAN LETTER GHAN --> <!-- U+10E6: "ღ" GEORGIAN LETTER GHAN -->
<Key <Key
latin:keyLabel="&#x10E6;" latin:keyLabel="&#x10E6;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="4" latin:keyHintLabel="4"
latin:additionalMoreKeys="4" /> latin:additionalMoreKeys="4" />
<!-- U+10D7: "თ" GEORGIAN LETTER TAN --> <!-- U+10D7: "თ" GEORGIAN LETTER TAN -->
<Key <Key
latin:keyLabel="&#x10D7;" latin:keyLabel="&#x10D7;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="5" latin:keyHintLabel="5"
latin:additionalMoreKeys="5" /> latin:additionalMoreKeys="5" />
<Key <Key
latin:keyLabel="Y" latin:keyLabel="Y"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="6" latin:keyHintLabel="6"
latin:additionalMoreKeys="6" /> latin:additionalMoreKeys="6" />
<Key <Key
latin:keyLabel="U" latin:keyLabel="U"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="7" latin:keyHintLabel="7"
latin:additionalMoreKeys="7" /> latin:additionalMoreKeys="7" />
<Key <Key
latin:keyLabel="I" latin:keyLabel="I"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="8" latin:keyHintLabel="8"
latin:additionalMoreKeys="8" /> latin:additionalMoreKeys="8" />
<Key <Key
latin:keyLabel="O" latin:keyLabel="O"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="9" latin:keyHintLabel="9"
latin:additionalMoreKeys="9" /> latin:additionalMoreKeys="9" />
<Key <Key
latin:keyLabel="P" latin:keyLabel="P"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="0" latin:keyHintLabel="0"
latin:additionalMoreKeys="0" /> latin:additionalMoreKeys="0" />
</case> </case>
@ -83,13 +73,11 @@
<!-- U+10E5: "ქ" GEORGIAN LETTER GHAN --> <!-- U+10E5: "ქ" GEORGIAN LETTER GHAN -->
<Key <Key
latin:keyLabel="&#x10E5;" latin:keyLabel="&#x10E5;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="1" latin:keyHintLabel="1"
latin:additionalMoreKeys="1" /> latin:additionalMoreKeys="1" />
<!-- U+10EC: "წ" GEORGIAN LETTER CIL --> <!-- U+10EC: "წ" GEORGIAN LETTER CIL -->
<Key <Key
latin:keyLabel="&#x10EC;" latin:keyLabel="&#x10EC;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="2" latin:keyHintLabel="2"
latin:additionalMoreKeys="2" /> latin:additionalMoreKeys="2" />
<!-- U+10D4: "ე" GEORGIAN LETTER EN <!-- U+10D4: "ე" GEORGIAN LETTER EN
@ -97,19 +85,16 @@
<Key <Key
latin:keyLabel="&#x10D4;" latin:keyLabel="&#x10D4;"
latin:moreKeys="&#x10F1;" latin:moreKeys="&#x10F1;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="3" latin:keyHintLabel="3"
latin:additionalMoreKeys="3" /> latin:additionalMoreKeys="3" />
<!-- U+10E0: "რ" GEORGIAN LETTER RAE --> <!-- U+10E0: "რ" GEORGIAN LETTER RAE -->
<Key <Key
latin:keyLabel="&#x10E0;" latin:keyLabel="&#x10E0;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="4" latin:keyHintLabel="4"
latin:additionalMoreKeys="4" /> latin:additionalMoreKeys="4" />
<!-- U+10E2: "ტ" GEORGIAN LETTER TAR --> <!-- U+10E2: "ტ" GEORGIAN LETTER TAR -->
<Key <Key
latin:keyLabel="&#x10E2;" latin:keyLabel="&#x10E2;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="5" latin:keyHintLabel="5"
latin:additionalMoreKeys="5" /> latin:additionalMoreKeys="5" />
<!-- U+10E7: "" GEORGIAN LETTER QAR <!-- U+10E7: "" GEORGIAN LETTER QAR
@ -117,13 +102,11 @@
<Key <Key
latin:keyLabel="&#x10E7;" latin:keyLabel="&#x10E7;"
latin:moreKeys="&#x10F8;" latin:moreKeys="&#x10F8;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="6" latin:keyHintLabel="6"
latin:additionalMoreKeys="6" /> latin:additionalMoreKeys="6" />
<!-- U+10E3: "უ" GEORGIAN LETTER UN --> <!-- U+10E3: "უ" GEORGIAN LETTER UN -->
<Key <Key
latin:keyLabel="&#x10E3;" latin:keyLabel="&#x10E3;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="7" latin:keyHintLabel="7"
latin:additionalMoreKeys="7" /> latin:additionalMoreKeys="7" />
<!-- U+10D8: "ი" GEORGIAN LETTER IN <!-- U+10D8: "ი" GEORGIAN LETTER IN
@ -131,19 +114,16 @@
<Key <Key
latin:keyLabel="&#x10D8;" latin:keyLabel="&#x10D8;"
latin:moreKeys="&#x10F2;" latin:moreKeys="&#x10F2;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="8" latin:keyHintLabel="8"
latin:additionalMoreKeys="8" /> latin:additionalMoreKeys="8" />
<!-- U+10DD: "ო" GEORGIAN LETTER ON --> <!-- U+10DD: "ო" GEORGIAN LETTER ON -->
<Key <Key
latin:keyLabel="&#x10DD;" latin:keyLabel="&#x10DD;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="9" latin:keyHintLabel="9"
latin:additionalMoreKeys="9" /> latin:additionalMoreKeys="9" />
<!-- U+10DE: "პ" GEORGIAN LETTER PAR --> <!-- U+10DE: "პ" GEORGIAN LETTER PAR -->
<Key <Key
latin:keyLabel="&#x10DE;" latin:keyLabel="&#x10DE;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="0" latin:keyHintLabel="0"
latin:additionalMoreKeys="0" /> latin:additionalMoreKeys="0" />
</default> </default>

View File

@ -26,82 +26,64 @@
latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
> >
<Key <Key
latin:keyLabel="A" latin:keyLabel="A" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10E8: "შ" GEORGIAN LETTER SHIN --> <!-- U+10E8: "შ" GEORGIAN LETTER SHIN -->
<Key <Key
latin:keyLabel="&#x10E8;" latin:keyLabel="&#x10E8;" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="D" latin:keyLabel="D" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="F" latin:keyLabel="F" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="G" latin:keyLabel="G" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="H" latin:keyLabel="H" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10DF: "ჟ" GEORGIAN LETTER ZHAR --> <!-- U+10DF: "ჟ" GEORGIAN LETTER ZHAR -->
<Key <Key
latin:keyLabel="&#x10DF;" latin:keyLabel="&#x10DF;" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="K" latin:keyLabel="K" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="L" latin:keyLabel="L" />
latin:keyLabelFlags="preserveCase" />
</case> </case>
<default> <default>
<!-- U+10D0: "ა" GEORGIAN LETTER AN <!-- U+10D0: "ა" GEORGIAN LETTER AN
U+10FA: "ჺ" GEORGIAN LETTER AIN --> U+10FA: "ჺ" GEORGIAN LETTER AIN -->
<Key <Key
latin:keyLabel="&#x10D0;" latin:keyLabel="&#x10D0;"
latin:moreKeys="&#x10FA;" latin:moreKeys="&#x10FA;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10E1: "ს" GEORGIAN LETTER SAN --> <!-- U+10E1: "ს" GEORGIAN LETTER SAN -->
<Key <Key
latin:keyLabel="&#x10E1;" latin:keyLabel="&#x10E1;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10D3: "დ" GEORGIAN LETTER DON --> <!-- U+10D3: "დ" GEORGIAN LETTER DON -->
<Key <Key
latin:keyLabel="&#x10D3;" latin:keyLabel="&#x10D3;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10E4: "ფ" GEORGIAN LETTER PHAR <!-- U+10E4: "ფ" GEORGIAN LETTER PHAR
U+10F6: "ჶ" GEORGIAN LETTER FI --> U+10F6: "ჶ" GEORGIAN LETTER FI -->
<Key <Key
latin:keyLabel="&#x10E4;" latin:keyLabel="&#x10E4;"
latin:moreKeys="&#x10F6;" latin:moreKeys="&#x10F6;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10D2: "გ" GEORGIAN LETTER GAN <!-- U+10D2: "გ" GEORGIAN LETTER GAN
U+10F9: "ჹ" GEORGIAN LETTER TURNED GAN --> U+10F9: "ჹ" GEORGIAN LETTER TURNED GAN -->
<Key <Key
latin:keyLabel="&#x10D2;" latin:keyLabel="&#x10D2;"
latin:moreKeys="&#x10F9;" latin:moreKeys="&#x10F9;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10F0: "ჰ" GEORGIAN LETTER HAE <!-- U+10F0: "ჰ" GEORGIAN LETTER HAE
U+10F5: "ჵ" GEORGIAN LETTER HOE --> U+10F5: "ჵ" GEORGIAN LETTER HOE -->
<Key <Key
latin:keyLabel="&#x10F0;" latin:keyLabel="&#x10F0;"
latin:moreKeys="&#x10F5;" latin:moreKeys="&#x10F5;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10EF: "ჯ" GEORGIAN LETTER JHAN <!-- U+10EF: "ჯ" GEORGIAN LETTER JHAN
U+10F7: "ჷ" GEORGIAN LETTER YN --> U+10F7: "ჷ" GEORGIAN LETTER YN -->
<Key <Key
latin:keyLabel="&#x10EF;" latin:keyLabel="&#x10EF;"
latin:moreKeys="&#x10F7;" latin:moreKeys="&#x10F7;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10D9: "კ" GEORGIAN LETTER KAN --> <!-- U+10D9: "კ" GEORGIAN LETTER KAN -->
<Key <Key
latin:keyLabel="&#x10D9;" latin:keyLabel="&#x10D9;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10DA: "ლ" GEORGIAN LETTER LAS --> <!-- U+10DA: "ლ" GEORGIAN LETTER LAS -->
<Key <Key
latin:keyLabel="&#x10DA;" latin:keyLabel="&#x10DA;" />
latin:keyLabelFlags="preserveCase" />
</default> </default>
</switch> </switch>
</merge> </merge>

View File

@ -27,63 +27,49 @@
> >
<!-- U+10EB: "ძ" GEORGIAN LETTER JIL --> <!-- U+10EB: "ძ" GEORGIAN LETTER JIL -->
<Key <Key
latin:keyLabel="&#x10EB;" latin:keyLabel="&#x10EB;" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="X" latin:keyLabel="X" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10E9: "ჩ" GEORGIAN LETTER CHIN --> <!-- U+10E9: "ჩ" GEORGIAN LETTER CHIN -->
<Key <Key
latin:keyLabel="&#x10E9;" latin:keyLabel="&#x10E9;" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="V" latin:keyLabel="V" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="B" latin:keyLabel="B" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="N" latin:keyLabel="N" />
latin:keyLabelFlags="preserveCase" />
<Key <Key
latin:keyLabel="M" latin:keyLabel="M" />
latin:keyLabelFlags="preserveCase" />
</case> </case>
<default> <default>
<!-- U+10D6: "ზ" GEORGIAN LETTER ZEN --> <!-- U+10D6: "ზ" GEORGIAN LETTER ZEN -->
<Key <Key
latin:keyLabel="&#x10D6;" latin:keyLabel="&#x10D6;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10EE: "ხ" GEORGIAN LETTER XAN <!-- U+10EE: "ხ" GEORGIAN LETTER XAN
U+10F4: "ჴ" GEORGIAN LETTER HAR --> U+10F4: "ჴ" GEORGIAN LETTER HAR -->
<Key <Key
latin:keyLabel="&#x10EE;" latin:keyLabel="&#x10EE;"
latin:moreKeys="&#x10F4;" latin:moreKeys="&#x10F4;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10EA: "ც" GEORGIAN LETTER CAN --> <!-- U+10EA: "ც" GEORGIAN LETTER CAN -->
<Key <Key
latin:keyLabel="&#x10EA;" latin:keyLabel="&#x10EA;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10D5: "ვ" GEORGIAN LETTER VIN <!-- U+10D5: "ვ" GEORGIAN LETTER VIN
U+10F3: "ჳ" GEORGIAN LETTER WE --> U+10F3: "ჳ" GEORGIAN LETTER WE -->
<Key <Key
latin:keyLabel="&#x10D5;" latin:keyLabel="&#x10D5;"
latin:moreKeys="&#x10F3;" latin:moreKeys="&#x10F3;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10D1: "ბ" GEORGIAN LETTER BAN --> <!-- U+10D1: "ბ" GEORGIAN LETTER BAN -->
<Key <Key
latin:keyLabel="&#x10D1;" latin:keyLabel="&#x10D1;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10DC: "ნ" GEORGIAN LETTER NAR <!-- U+10DC: "ნ" GEORGIAN LETTER NAR
U+10FC: "ჼ" MODIFIER LETTER GEORGIAN NAR --> U+10FC: "ჼ" MODIFIER LETTER GEORGIAN NAR -->
<Key <Key
latin:keyLabel="&#x10DC;" latin:keyLabel="&#x10DC;"
latin:moreKeys="&#x10FC;" latin:moreKeys="&#x10FC;" />
latin:keyLabelFlags="preserveCase" />
<!-- U+10DB: "მ" GEORGIAN LETTER MAN --> <!-- U+10DB: "მ" GEORGIAN LETTER MAN -->
<Key <Key
latin:keyLabel="&#x10DB;" latin:keyLabel="&#x10DB;" />
latin:keyLabelFlags="preserveCase" />
</default> </default>
</switch> </switch>
</merge> </merge>

View File

@ -76,7 +76,7 @@ public class KeySpecParser {
} }
private static boolean hasIcon(String moreKeySpec) { private static boolean hasIcon(String moreKeySpec) {
if (moreKeySpec.startsWith(PREFIX_ICON)) { if (moreKeySpec.regionMatches(true, 0, PREFIX_ICON, 0, PREFIX_ICON.length())) {
final int end = indexOfLabelEnd(moreKeySpec, 0); final int end = indexOfLabelEnd(moreKeySpec, 0);
if (end > 0) { if (end > 0) {
return true; return true;
@ -88,8 +88,8 @@ public class KeySpecParser {
private static boolean hasCode(String moreKeySpec) { private static boolean hasCode(String moreKeySpec) {
final int end = indexOfLabelEnd(moreKeySpec, 0); final int end = indexOfLabelEnd(moreKeySpec, 0);
if (end > 0 && end + 1 < moreKeySpec.length() if (end > 0 && end + 1 < moreKeySpec.length() && moreKeySpec.regionMatches(
&& moreKeySpec.substring(end + 1).startsWith(PREFIX_CODE)) { true, end + 1, PREFIX_CODE, 0, PREFIX_CODE.length())) {
return true; return true;
} }
return false; return false;
@ -210,9 +210,9 @@ public class KeySpecParser {
public static int parseCode(String text, KeyboardCodesSet codesSet, int defCode) { public static int parseCode(String text, KeyboardCodesSet codesSet, int defCode) {
if (text == null) return defCode; if (text == null) return defCode;
if (text.startsWith(PREFIX_CODE)) { if (text.regionMatches(true, 0, PREFIX_CODE, 0, PREFIX_CODE.length())) {
return codesSet.getCode(text.substring(PREFIX_CODE.length())); return codesSet.getCode(text.substring(PREFIX_CODE.length()));
} else if (text.startsWith(PREFIX_HEX)) { } else if (text.regionMatches(true, 0, PREFIX_HEX, 0, PREFIX_HEX.length())) {
return Integer.parseInt(text.substring(PREFIX_HEX.length()), 16); return Integer.parseInt(text.substring(PREFIX_HEX.length()), 16);
} else { } else {
return Integer.parseInt(text); return Integer.parseInt(text);
@ -350,20 +350,22 @@ public class KeySpecParser {
throw new RuntimeException("too many @string/resource indirection: " + text); throw new RuntimeException("too many @string/resource indirection: " + text);
} }
final int prefixLen = PREFIX_LABEL.length();
final int size = text.length(); final int size = text.length();
if (size < PREFIX_LABEL.length()) { if (size < prefixLen) {
return text; return text;
} }
sb = null; sb = null;
for (int pos = 0; pos < size; pos++) { for (int pos = 0; pos < size; pos++) {
final char c = text.charAt(pos); final char c = text.charAt(pos);
if (text.startsWith(PREFIX_LABEL, pos) && labelsSet != null) { if (text.regionMatches(true, pos, PREFIX_LABEL, 0, prefixLen)
&& labelsSet != null) {
if (sb == null) { if (sb == null) {
sb = new StringBuilder(text.substring(0, pos)); sb = new StringBuilder(text.substring(0, pos));
} }
final int end = searchLabelNameEnd(text, pos + PREFIX_LABEL.length()); final int end = searchLabelNameEnd(text, pos + prefixLen);
final String name = text.substring(pos + PREFIX_LABEL.length(), end); final String name = text.substring(pos + prefixLen, end);
sb.append(labelsSet.getLabel(name)); sb.append(labelsSet.getLabel(name));
pos = end - 1; pos = end - 1;
} else if (c == ESCAPE_CHAR) { } else if (c == ESCAPE_CHAR) {
@ -389,8 +391,9 @@ public class KeySpecParser {
final int size = text.length(); final int size = text.length();
for (int pos = start; pos < size; pos++) { for (int pos = start; pos < size; pos++) {
final char c = text.charAt(pos); final char c = text.charAt(pos);
// String resource name should be consisted of [a-z_0-9]. // Label name should be consisted of [a-zA-Z_0-9].
if ((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) { if ((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')
|| (c >= 'A' && c <= 'Z')) {
continue; continue;
} }
return pos; return pos;
@ -442,17 +445,19 @@ public class KeySpecParser {
if (moreKeys == null) { if (moreKeys == null) {
return defaultValue; return defaultValue;
} }
final int keyLen = key.length();
boolean foundValue = false; boolean foundValue = false;
int value = defaultValue; int value = defaultValue;
for (int i = 0; i < moreKeys.length; i++) { for (int i = 0; i < moreKeys.length; i++) {
final String moreKeySpec = moreKeys[i]; final String moreKeySpec = moreKeys[i];
if (moreKeySpec == null || !moreKeySpec.startsWith(key)) { if (moreKeySpec == null || !moreKeySpec.regionMatches(true, 0, key, 0, keyLen)) {
continue; continue;
} }
moreKeys[i] = null; moreKeys[i] = null;
try { try {
if (!foundValue) { if (!foundValue) {
value = Integer.parseInt(moreKeySpec.substring(key.length())); value = Integer.parseInt(moreKeySpec.substring(keyLen));
foundValue = true;
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new RuntimeException( throw new RuntimeException(
@ -469,7 +474,7 @@ public class KeySpecParser {
boolean value = false; boolean value = false;
for (int i = 0; i < moreKeys.length; i++) { for (int i = 0; i < moreKeys.length; i++) {
final String moreKeySpec = moreKeys[i]; final String moreKeySpec = moreKeys[i];
if (moreKeySpec == null || !moreKeySpec.equals(key)) { if (moreKeySpec == null || !moreKeySpec.equalsIgnoreCase(key)) {
continue; continue;
} }
moreKeys[i] = null; moreKeys[i] = null;

View File

@ -33,7 +33,10 @@ public class KeyboardCodesSet {
} }
public int getCode(final String name) { public int getCode(final String name) {
final Integer id = sNameToIdMap.get(name); Integer id = sNameToIdMap.get(name);
if (id == null) {
id = sNameToIdMap.get(name.toLowerCase());
}
if (id == null) throw new RuntimeException("Unknown key code: " + name); if (id == null) throw new RuntimeException("Unknown key code: " + name);
return mCodes[id]; return mCodes[id];
} }

View File

@ -36,7 +36,9 @@ public class KeyboardIconsSet {
private static final HashMap<Integer, Integer> ATTR_ID_TO_ICON_ID private static final HashMap<Integer, Integer> ATTR_ID_TO_ICON_ID
= new HashMap<Integer, Integer>(); = new HashMap<Integer, Integer>();
private static final HashMap<String, Integer> NAME_TO_ICON_ID = new HashMap<String, Integer>(); // Lower case icon name to icon id map.
private static final HashMap<String, Integer> sLowerCaseNameToIdsMap =
new HashMap<String, Integer>();
private static final String[] ICON_NAMES = new String[NUM_ICONS + 1]; private static final String[] ICON_NAMES = new String[NUM_ICONS + 1];
private static final int ATTR_UNDEFINED = 0; private static final int ATTR_UNDEFINED = 0;
@ -66,7 +68,7 @@ public class KeyboardIconsSet {
if (attrId != ATTR_UNDEFINED) { if (attrId != ATTR_UNDEFINED) {
ATTR_ID_TO_ICON_ID.put(attrId, iconId); ATTR_ID_TO_ICON_ID.put(attrId, iconId);
} }
NAME_TO_ICON_ID.put(name, iconId); sLowerCaseNameToIdsMap.put(name.toLowerCase(), iconId);
ICON_NAMES[iconId] = name; ICON_NAMES[iconId] = name;
} }
@ -94,7 +96,10 @@ public class KeyboardIconsSet {
} }
public static int getIconId(final String name) { public static int getIconId(final String name) {
final Integer iconId = NAME_TO_ICON_ID.get(name); Integer iconId = sLowerCaseNameToIdsMap.get(name);
if (iconId == null) {
iconId = sLowerCaseNameToIdsMap.get(name.toLowerCase());
}
if (iconId != null) { if (iconId != null) {
return iconId; return iconId;
} }

View File

@ -31,7 +31,8 @@ public final class KeyboardLabelsSet {
// Language to labels map. // Language to labels map.
private static final HashMap<String, String[]> sLocaleToLabelsMap = private static final HashMap<String, String[]> sLocaleToLabelsMap =
new HashMap<String, String[]>(); new HashMap<String, String[]>();
private static final HashMap<String, Integer> sNameToIdMap = new HashMap<String, Integer>(); private static final HashMap<String, Integer> sLowerCaseNameToIdsMap =
new HashMap<String, Integer>();
private String[] mLabels; private String[] mLabels;
// Resource name to label map. // Resource name to label map.
@ -60,12 +61,21 @@ public final class KeyboardLabelsSet {
} }
public String getLabel(final String name) { public String getLabel(final String name) {
if (mResourceNameToLabelsMap.containsKey(name)) { String lowerCaseName = null;
return mResourceNameToLabelsMap.get(name); String label = mResourceNameToLabelsMap.get(name);
if (label == null) {
lowerCaseName = name.toLowerCase();
label = mResourceNameToLabelsMap.get(lowerCaseName);
}
if (label != null) {
return label;
}
Integer id = sLowerCaseNameToIdsMap.get(name);
if (id == null) {
id = sLowerCaseNameToIdsMap.get(lowerCaseName); // lowerCaseName != null
} }
final Integer id = sNameToIdMap.get(name);
if (id == null) throw new RuntimeException("Unknown label: " + name); if (id == null) throw new RuntimeException("Unknown label: " + name);
final String label = (id < mLabels.length) ? mLabels[id] : null; label = (id < mLabels.length) ? mLabels[id] : null;
return (label == null) ? LANGUAGE_DEFAULT[id] : label; return (label == null) ? LANGUAGE_DEFAULT[id] : label;
} }
@ -2492,7 +2502,7 @@ public final class KeyboardLabelsSet {
static { static {
int id = 0; int id = 0;
for (final String name : NAMES) { for (final String name : NAMES) {
sNameToIdMap.put(name, id++); sLowerCaseNameToIdsMap.put(name, id++);
} }
for (int i = 0; i < LANGUAGES_AND_LABELS.length; i += 2) { for (int i = 0; i < LANGUAGES_AND_LABELS.length; i += 2) {

View File

@ -52,5 +52,11 @@
<string name="multiple_labels_with_comma_and_escape_surrounded_by_spaces">" ab\\\\ , d\\\\\\, , g\\,i "</string> <string name="multiple_labels_with_comma_and_escape_surrounded_by_spaces">" ab\\\\ , d\\\\\\, , g\\,i "</string>
<string name="indirect_string">!label/multiple_chars</string> <string name="indirect_string">!label/multiple_chars</string>
<string name="indirect_string_with_literal">x,!label/multiple_chars,y</string> <string name="indirect_string_with_literal">x,!label/multiple_chars,y</string>
<string name="indirect2_string">!label/indirect_string</string>
<string name="infinite_indirection">infinite,!label/infinite_indirection,loop</string> <string name="infinite_indirection">infinite,!label/infinite_indirection,loop</string>
<string name="upper_indirect_string">!LABEL/MULTIPLE_CHARS</string>
<string name="upper_indirect_string_with_literal">x,!LABEL/MULTIPLE_CHARS,y</string>
<string name="upper_indirect2_string">!LABEL/UPPER_INDIRECT_STRING</string>
<string name="upper_infinite_indirection">infinite,!LABEL/INFINITE_INDIRECTION,loop</string>
<string name="indirect_navigate_actions_as_more_key">!fixedColumnOrder!2,!label/action_previous_as_more_key,!label/action_next_as_more_key</string>
</resources> </resources>

View File

@ -17,7 +17,6 @@
package com.android.inputmethod.keyboard.internal; package com.android.inputmethod.keyboard.internal;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import android.text.TextUtils;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
@ -32,6 +31,7 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
super.setUp(); super.setUp();
mLabelsSet.setLanguage(Locale.ENGLISH.getLanguage()); mLabelsSet.setLanguage(Locale.ENGLISH.getLanguage());
mLabelsSet.loadStringResources(getContext());
final String[] testResourceNames = getAllResourceIdNames( final String[] testResourceNames = getAllResourceIdNames(
com.android.inputmethod.latin.tests.R.string.class); com.android.inputmethod.latin.tests.R.string.class);
mLabelsSet.loadStringResourcesInternal(getTestContext(), mLabelsSet.loadStringResourcesInternal(getTestContext(),
@ -49,20 +49,28 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
return names.toArray(new String[names.size()]); return names.toArray(new String[names.size()]);
} }
private void assertTextArray(String message, String value, String ... expected) { private static void assertArrayEquals(String message, Object[] expected, Object[] actual) {
final String actual[] = KeySpecParser.parseCsvString(value, mLabelsSet); if (expected == actual) {
if (expected.length == 0) {
assertNull(message + ": expected=null actual=" + Arrays.toString(actual),
actual);
return; return;
} }
assertEquals(message + ": expected=" + Arrays.toString(expected) if (expected == null || actual == null) {
+ " actual=" + Arrays.toString(actual) assertEquals(message, Arrays.toString(expected), Arrays.toString(actual));
+ ": result length", expected.length, actual.length); return;
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);
} }
if (expected.length != actual.length) {
assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual));
return;
}
for (int i = 0; i < expected.length; i++) {
assertEquals(message + " [" + i + "]",
Arrays.toString(expected), Arrays.toString(actual));
}
}
private void assertTextArray(String message, String value, String ... expectedArray) {
final String[] actual = KeySpecParser.parseCsvString(value, mLabelsSet);
final String[] expected = (expectedArray.length == 0) ? null : expectedArray;
assertArrayEquals(message, expected, actual);
} }
private void assertError(String message, String value, String ... expected) { private void assertError(String message, String value, String ... expected) {
@ -116,6 +124,7 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
assertTextArray("Incomplete resource reference 1", "label", "label"); assertTextArray("Incomplete resource reference 1", "label", "label");
assertTextArray("Incomplete resource reference 2", "!label", "!label"); assertTextArray("Incomplete resource reference 2", "!label", "!label");
assertTextArray("Incomplete RESOURCE REFERENCE 2", "!LABEL", "!LABEL");
assertTextArray("Incomplete resource reference 3", "label/", "label/"); assertTextArray("Incomplete resource reference 3", "label/", "label/");
assertTextArray("Incomplete resource reference 4", "!" + SURROGATE2, "!" + SURROGATE2); assertTextArray("Incomplete resource reference 4", "!" + SURROGATE2, "!" + SURROGATE2);
} }
@ -150,7 +159,9 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
assertTextArray("Escaped !label", "\\!label", "\\!label"); assertTextArray("Escaped !label", "\\!label", "\\!label");
assertTextArray("Escaped !label/", "\\!label/", "\\!label/"); assertTextArray("Escaped !label/", "\\!label/", "\\!label/");
assertTextArray("Escaped !label/", "\\!label/empty_string", "\\!label/empty_string"); assertTextArray("Escaped !LABEL/", "\\!LABEL/", "\\!LABEL/");
assertTextArray("Escaped !label/name", "\\!label/empty_string", "\\!label/empty_string");
assertTextArray("Escaped !LABEL/NAME", "\\!LABEL/EMPTY_STRING", "\\!LABEL/EMPTY_STRING");
} }
public void testParseCsvTextMulti() { public void testParseCsvTextMulti() {
@ -183,6 +194,8 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
assertTextArray("Multiple escaped !label", "\\!,\\!label/empty_string", assertTextArray("Multiple escaped !label", "\\!,\\!label/empty_string",
"\\!", "\\!label/empty_string"); "\\!", "\\!label/empty_string");
assertTextArray("Multiple escaped !LABEL", "\\!,\\!LABEL/EMPTY_STRING",
"\\!", "\\!LABEL/EMPTY_STRING");
} }
public void testParseCsvResourceError() { public void testParseCsvResourceError() {
@ -193,11 +206,15 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
public void testParseCsvResourceZero() { public void testParseCsvResourceZero() {
assertTextArray("Empty string", assertTextArray("Empty string",
"!label/empty_string"); "!label/empty_string");
assertTextArray("EMPTY STRING",
"!LABEL/EMPTY_STRING");
} }
public void testParseCsvResourceSingle() { public void testParseCsvResourceSingle() {
assertTextArray("Single char", assertTextArray("Single char",
"!label/single_char", "a"); "!label/single_char", "a");
assertTextArray("SINGLE CHAR",
"!LABEL/SINGLE_CHAR", "a");
assertTextArray("Space", assertTextArray("Space",
"!label/space", " "); "!label/space", " ");
assertTextArray("Single label", assertTextArray("Single label",
@ -215,6 +232,8 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
assertTextArray("Escape and single char", assertTextArray("Escape and single char",
"\\\\!label/single_char", "\\\\a"); "\\\\!label/single_char", "\\\\a");
assertTextArray("Escape and SINGLE CHAR",
"\\\\!LABEL/SINGLE_CHAR", "\\\\a");
} }
public void testParseCsvResourceSingleEscaped() { public void testParseCsvResourceSingleEscaped() {
@ -247,6 +266,8 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
public void testParseCsvResourceMulti() { public void testParseCsvResourceMulti() {
assertTextArray("Multiple chars", assertTextArray("Multiple chars",
"!label/multiple_chars", "a", "b", "c"); "!label/multiple_chars", "a", "b", "c");
assertTextArray("MULTIPLE CHARS",
"!LABEL/MULTIPLE_CHARS", "a", "b", "c");
assertTextArray("Multiple chars surrounded by spaces", assertTextArray("Multiple chars surrounded by spaces",
"!label/multiple_chars_surrounded_by_spaces", "!label/multiple_chars_surrounded_by_spaces",
" a ", " b ", " c "); " a ", " b ", " c ");
@ -280,6 +301,8 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
public void testParseMultipleResources() { public void testParseMultipleResources() {
assertTextArray("Literals and resources", assertTextArray("Literals and resources",
"1,!label/multiple_chars,z", "1", "a", "b", "c", "z"); "1,!label/multiple_chars,z", "1", "a", "b", "c", "z");
assertTextArray("Literals and RESOURCES",
"1,!LABEL/MULTIPLE_CHARS,z", "1", "a", "b", "c", "z");
assertTextArray("Literals and resources and escape at end", assertTextArray("Literals and resources and escape at end",
"\\1,!label/multiple_chars,z\\", "\\1", "a", "b", "c", "z\\"); "\\1,!label/multiple_chars,z\\", "\\1", "a", "b", "c", "z\\");
assertTextArray("Multiple single resource chars and labels", assertTextArray("Multiple single resource chars and labels",
@ -288,6 +311,9 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
assertTextArray("Multiple single resource chars and labels 2", assertTextArray("Multiple single resource chars and labels 2",
"!label/single_char,!label/single_label,!label/escaped_comma_escape", "!label/single_char,!label/single_label,!label/escaped_comma_escape",
"a", "abc", "a\\,\\"); "a", "abc", "a\\,\\");
assertTextArray("Multiple single RESOURCE chars and LABELS 2",
"!LABEL/SINGLE_CHAR,!LABEL/SINGLE_LABEL,!LABEL/ESCAPED_COMMA_ESCAPE",
"a", "abc", "a\\,\\");
assertTextArray("Multiple multiple resource chars and labels", assertTextArray("Multiple multiple resource chars and labels",
"!label/multiple_chars,!label/multiple_labels,!label/multiple_chars_with_comma", "!label/multiple_chars,!label/multiple_labels,!label/multiple_chars_with_comma",
"a", "b", "c", "abc", "def", "ghi", "a", "\\,", "c"); "a", "b", "c", "abc", "def", "ghi", "a", "\\,", "c");
@ -304,10 +330,68 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
"!label/indirect_string", "a", "b", "c"); "!label/indirect_string", "a", "b", "c");
assertTextArray("Indirect with literal", assertTextArray("Indirect with literal",
"1,!label/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2"); "1,!label/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2");
assertTextArray("Indirect2",
"!label/indirect2_string", "a", "b", "c");
assertTextArray("INDIRECT",
"!LABEL/INDIRECT_STRING", "a", "b", "c");
assertTextArray("INDIRECT with literal",
"1,!LABEL/INDIRECT_STRING_WITH_LITERAL,2", "1", "x", "a", "b", "c", "y", "2");
assertTextArray("INDIRECT2",
"!LABEL/INDIRECT2_STRING", "a", "b", "c");
assertTextArray("Upper indirect",
"!label/upper_indirect_string", "a", "b", "c");
assertTextArray("Upper indirect with literal",
"1,!label/upper_indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2");
assertTextArray("Upper indirect2",
"!label/upper_indirect2_string", "a", "b", "c");
assertTextArray("UPPER INDIRECT",
"!LABEL/upper_INDIRECT_STRING", "a", "b", "c");
assertTextArray("Upper INDIRECT with literal",
"1,!LABEL/upper_INDIRECT_STRING_WITH_LITERAL,2", "1", "x", "a", "b", "c", "y", "2");
assertTextArray("Upper INDIRECT2",
"!LABEL/upper_INDIRECT2_STRING", "a", "b", "c");
} }
public void testParseInfiniteIndirectReference() { public void testParseInfiniteIndirectReference() {
assertError("Infinite indirection", assertError("Infinite indirection",
"1,!label/infinite_indirection,2", "1", "infinite", "<infinite>", "loop", "2"); "1,!label/infinite_indirection,2", "1", "infinite", "<infinite>", "loop", "2");
assertError("INFINITE INDIRECTION",
"1,!LABEL/INFINITE_INDIRECTION,2", "1", "infinite", "<infinite>", "loop", "2");
assertError("Upper infinite indirection",
"1,!label/upper_infinite_indirection,2",
"1", "infinite", "<infinite>", "loop", "2");
assertError("Upper INFINITE INDIRECTION",
"1,!LABEL/UPPER_INFINITE_INDIRECTION,2",
"1", "infinite", "<infinite>", "loop", "2");
}
public void testLabelReferece() {
assertTextArray("Label time am", "!label/label_time_am", "AM");
assertTextArray("LABEL TIME AM", "!LABEL/LABEL_TIME_AM", "AM");
assertTextArray("More keys for am pm", "!label/more_keys_for_am_pm",
"!fixedColumnOrder!2", "!hasLabels!", "AM", "PM");
assertTextArray("MORE KEYS FOR AM OM", "!LABEL/MORE_KEYS_FOR_AM_PM",
"!fixedColumnOrder!2", "!hasLabels!", "AM", "PM");
assertTextArray("Settings as more key", "!label/settings_as_more_key",
"!icon/settingsKey|!code/key_settings");
assertTextArray("SETTINGS AS MORE KEY", "!LABEL/SETTINGS_AS_MORE_KEY",
"!icon/settingsKey|!code/key_settings");
assertTextArray("Indirect naviagte actions as more key",
"!label/indirect_navigate_actions_as_more_key",
"!fixedColumnOrder!2",
"!hasLabels!", "Prev|!code/key_action_previous",
"!hasLabels!", "Next|!code/key_action_next");
assertTextArray("INDIRECT NAVIGATE ACTIONS AS MORE KEY",
"!LABEL/INDIRECT_NAVIGATE_ACTIONS_AS_MORE_KEY",
"!fixedColumnOrder!2",
"!hasLabels!", "Prev|!code/key_action_previous",
"!hasLabels!", "Next|!code/key_action_next");
} }
} }

View File

@ -16,9 +16,12 @@
package com.android.inputmethod.keyboard.internal; package com.android.inputmethod.keyboard.internal;
import static com.android.inputmethod.keyboard.Keyboard.CODE_OUTPUT_TEXT;
import static com.android.inputmethod.keyboard.Keyboard.CODE_UNSPECIFIED;
import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec; import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
import java.util.Arrays; import java.util.Arrays;
@ -26,32 +29,40 @@ import java.util.Locale;
public class KeySpecParserTests extends AndroidTestCase { public class KeySpecParserTests extends AndroidTestCase {
private final KeyboardCodesSet mCodesSet = new KeyboardCodesSet(); private final KeyboardCodesSet mCodesSet = new KeyboardCodesSet();
private final KeyboardLabelsSet mLabelsSet = new KeyboardLabelsSet();
private static final int ICON_UNDEFINED = KeyboardIconsSet.ICON_UNDEFINED;
private static final String CODE_SETTINGS_NAME = "key_settings"; private static final String CODE_SETTINGS_NAME = "key_settings";
private static final String ICON_SETTINGS_NAME = "settingsKey"; private static final String ICON_SETTINGS_NAME = "settingsKey";
private static final String CODE_SETTINGS = "!code/" + CODE_SETTINGS_NAME; private static final String CODE_SETTINGS = "!code/" + CODE_SETTINGS_NAME;
private static final String ICON_SETTINGS = "!icon/" + ICON_SETTINGS_NAME; private static final String ICON_SETTINGS = "!icon/" + ICON_SETTINGS_NAME;
private static final String CODE_SETTINGS_UPPERCASE = CODE_SETTINGS.toUpperCase();
private static final String ICON_SETTINGS_UPPERCASE = ICON_SETTINGS.toUpperCase();
private static final String CODE_NON_EXISTING = "!code/non_existing"; private static final String CODE_NON_EXISTING = "!code/non_existing";
private static final String ICON_NON_EXISTING = "!icon/non_existing"; private static final String ICON_NON_EXISTING = "!icon/non_existing";
private int mCodeSettings; private int mCodeSettings;
private int mCodeActionNext;
private int mSettingsIconId; private int mSettingsIconId;
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
mCodesSet.setLanguage(Locale.ENGLISH.getLanguage()); final String language = Locale.ENGLISH.getLanguage();
mCodesSet.setLanguage(language);
mLabelsSet.setLanguage(language);
mLabelsSet.loadStringResources(getContext());
mCodeSettings = mCodesSet.getCode(CODE_SETTINGS_NAME); mCodeSettings = mCodesSet.getCode(CODE_SETTINGS_NAME);
mCodeActionNext = mCodesSet.getCode("key_action_next");
mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME); mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME);
} }
private void assertParser(String message, String moreKeySpec, String expectedLabel, private void assertParser(String message, String moreKeySpec, String expectedLabel,
String expectedOutputText, int expectedIcon, int expectedCode) { String expectedOutputText, int expectedIcon, int expectedCode) {
final MoreKeySpec spec = new MoreKeySpec(moreKeySpec, mCodesSet); final MoreKeySpec spec = new MoreKeySpec(
KeySpecParser.resolveLabelReference(moreKeySpec, mLabelsSet), mCodesSet);
assertEquals(message + ": label:", expectedLabel, spec.mLabel); assertEquals(message + ": label:", expectedLabel, spec.mLabel);
assertEquals(message + ": ouptputText:", expectedOutputText, spec.mOutputText); assertEquals(message + ": ouptputText:", expectedOutputText, spec.mOutputText);
assertEquals(message + ": icon:", expectedIcon, spec.mIconId); assertEquals(message + ": icon:", expectedIcon, spec.mIconId);
@ -106,195 +117,253 @@ public class KeySpecParserTests extends AndroidTestCase {
assertParser("Single surrogate pair outputText", "G Clef|" + PAIR1, assertParser("Single surrogate pair outputText", "G Clef|" + PAIR1,
"G Clef", null, ICON_UNDEFINED, CODE1); "G Clef", null, ICON_UNDEFINED, CODE1);
assertParser("Single letter with outputText", "a|abc", assertParser("Single letter with outputText", "a|abc",
"a", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with surrogate outputText", "a|" + SURROGATE1, assertParser("Single letter with surrogate outputText", "a|" + SURROGATE1,
"a", SURROGATE1, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single surrogate with outputText", PAIR3 + "|abc", assertParser("Single surrogate with outputText", PAIR3 + "|abc",
PAIR3, "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); PAIR3, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with escaped outputText", "a|a\\|c", assertParser("Single letter with escaped outputText", "a|a\\|c",
"a", "a|c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with escaped surrogate outputText", assertParser("Single letter with escaped surrogate outputText",
"a|" + PAIR1 + "\\|" + PAIR2, "a|" + PAIR1 + "\\|" + PAIR2,
"a", PAIR1 + "|" + PAIR2, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", PAIR1 + "|" + PAIR2, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with comma outputText", "a|a,b", assertParser("Single letter with comma outputText", "a|a,b",
"a", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with escaped comma outputText", "a|a\\,b", assertParser("Single letter with escaped comma outputText", "a|a\\,b",
"a", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with outputText starts with bang", "a|!bc", assertParser("Single letter with outputText starts with bang", "a|!bc",
"a", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with surrogate outputText starts with bang", "a|!" + SURROGATE2, assertParser("Single letter with surrogate outputText starts with bang", "a|!" + SURROGATE2,
"a", "!" + SURROGATE2, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", "!" + SURROGATE2, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with outputText contains bang", "a|a!c", assertParser("Single letter with outputText contains bang", "a|a!c",
"a", "a!c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single letter with escaped bang outputText", "a|\\!bc", assertParser("Single letter with escaped bang outputText", "a|\\!bc",
"a", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Single escaped escape with single outputText", "\\\\|\\\\", assertParser("Single escaped escape with single outputText", "\\\\|\\\\",
"\\", null, ICON_UNDEFINED, '\\'); "\\", null, ICON_UNDEFINED, '\\');
assertParser("Single escaped bar with single outputText", "\\||\\|", assertParser("Single escaped bar with single outputText", "\\||\\|",
"|", null, ICON_UNDEFINED, '|'); "|", null, ICON_UNDEFINED, '|');
assertParser("Single letter with code", "a|" + CODE_SETTINGS, assertParser("Single letter with code", "a|" + CODE_SETTINGS,
"a", null, ICON_UNDEFINED, mCodeSettings); "a", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Single letter with CODE", "a|" + CODE_SETTINGS_UPPERCASE,
"a", null, ICON_UNDEFINED, mCodeSettings);
} }
public void testLabel() { public void testLabel() {
assertParser("Simple label", "abc", assertParser("Simple label", "abc",
"abc", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Simple surrogate label", SURROGATE1, assertParser("Simple surrogate label", SURROGATE1,
SURROGATE1, SURROGATE1, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); SURROGATE1, SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped bar", "a\\|c", assertParser("Label with escaped bar", "a\\|c",
"a|c", "a|c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a|c", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Surrogate label with escaped bar", PAIR1 + "\\|" + PAIR2, assertParser("Surrogate label with escaped bar", PAIR1 + "\\|" + PAIR2,
PAIR1 + "|" + PAIR2, PAIR1 + "|" + PAIR2, PAIR1 + "|" + PAIR2, PAIR1 + "|" + PAIR2,
ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped escape", "a\\\\c", assertParser("Label with escaped escape", "a\\\\c",
"a\\c", "a\\c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a\\c", "a\\c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with comma", "a,c", assertParser("Label with comma", "a,c",
"a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped comma", "a\\,c", assertParser("Label with escaped comma", "a\\,c",
"a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label starts with bang", "!bc", assertParser("Label starts with bang", "!bc",
"!bc", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Surrogate label starts with bang", "!" + SURROGATE1, assertParser("Surrogate label starts with bang", "!" + SURROGATE1,
"!" + SURROGATE1, "!" + SURROGATE1, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "!" + SURROGATE1, "!" + SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label contains bang", "a!c", assertParser("Label contains bang", "a!c",
"a!c", "a!c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a!c", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped bang", "\\!bc", assertParser("Label with escaped bang", "\\!bc",
"!bc", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped letter", "\\abc", assertParser("Label with escaped letter", "\\abc",
"abc", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with outputText", "abc|def", assertParser("Label with outputText", "abc|def",
"abc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with comma and outputText", "a,c|def", assertParser("Label with comma and outputText", "a,c|def",
"a,c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Escaped comma label with outputText", "a\\,c|def", assertParser("Escaped comma label with outputText", "a\\,c|def",
"a,c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Escaped label with outputText", "a\\|c|def", assertParser("Escaped label with outputText", "a\\|c|def",
"a|c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a|c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped bar outputText", "abc|d\\|f", assertParser("Label with escaped bar outputText", "abc|d\\|f",
"abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Escaped escape label with outputText", "a\\\\|def", assertParser("Escaped escape label with outputText", "a\\\\|def",
"a\\", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a\\", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label starts with bang and outputText", "!bc|def", assertParser("Label starts with bang and outputText", "!bc|def",
"!bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label contains bang label and outputText", "a!c|def", assertParser("Label contains bang label and outputText", "a!c|def",
"a!c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a!c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Escaped bang label with outputText", "\\!bc|def", assertParser("Escaped bang label with outputText", "\\!bc|def",
"!bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with comma outputText", "abc|a,b", assertParser("Label with comma outputText", "abc|a,b",
"abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped comma outputText", "abc|a\\,b", assertParser("Label with escaped comma outputText", "abc|a\\,b",
"abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with outputText starts with bang", "abc|!bc", assertParser("Label with outputText starts with bang", "abc|!bc",
"abc", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with outputText contains bang", "abc|a!c", assertParser("Label with outputText contains bang", "abc|a!c",
"abc", "a!c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped bang outputText", "abc|\\!bc", assertParser("Label with escaped bang outputText", "abc|\\!bc",
"abc", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with escaped bar outputText", "abc|d\\|f", assertParser("Label with escaped bar outputText", "abc|d\\|f",
"abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f",
"a|c", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); "a|c", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("Label with code", "abc|" + CODE_SETTINGS, assertParser("Label with code", "abc|" + CODE_SETTINGS,
"abc", null, ICON_UNDEFINED, mCodeSettings); "abc", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Label with CODE", "abc|" + CODE_SETTINGS_UPPERCASE,
"abc", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS, assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS,
"a|c", null, ICON_UNDEFINED, mCodeSettings); "a|c", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Escaped label with CODE", "a\\|c|" + CODE_SETTINGS_UPPERCASE,
"a|c", null, ICON_UNDEFINED, mCodeSettings);
} }
public void testIconAndCode() { public void testIconAndCode() {
assertParser("Icon with outputText", ICON_SETTINGS + "|abc", assertParser("Icon with outputText", ICON_SETTINGS + "|abc",
null, "abc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT); null, "abc", mSettingsIconId, CODE_OUTPUT_TEXT);
assertParser("ICON with outputText", ICON_SETTINGS_UPPERCASE + "|abc",
null, "abc", mSettingsIconId, CODE_OUTPUT_TEXT);
assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc", assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc",
null, "!bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT); null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT);
assertParser("ICON with outputText starts with bang", ICON_SETTINGS_UPPERCASE + "|!bc",
null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT);
assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c", assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c",
null, "a!c", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT); null, "a!c", mSettingsIconId, CODE_OUTPUT_TEXT);
assertParser("ICON with outputText contains bang", ICON_SETTINGS_UPPERCASE + "|a!c",
null, "a!c", mSettingsIconId, CODE_OUTPUT_TEXT);
assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc", assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc",
null, "!bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT); null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT);
assertParser("ICON with escaped bang outputText", ICON_SETTINGS_UPPERCASE + "|\\!bc",
null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT);
assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS, assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS,
"!bc", null, ICON_UNDEFINED, mCodeSettings); "!bc", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Label starts with bang and CODE", "!bc|" + CODE_SETTINGS_UPPERCASE,
"!bc", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS, assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS,
"a!c", null, ICON_UNDEFINED, mCodeSettings); "a!c", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Label contains bang and CODE", "a!c|" + CODE_SETTINGS_UPPERCASE,
"a!c", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Escaped bang label with code", "\\!bc|" + CODE_SETTINGS, assertParser("Escaped bang label with code", "\\!bc|" + CODE_SETTINGS,
"!bc", null, ICON_UNDEFINED, mCodeSettings); "!bc", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Escaped bang label with CODE", "\\!bc|" + CODE_SETTINGS_UPPERCASE,
"!bc", null, ICON_UNDEFINED, mCodeSettings);
assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS, assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS,
null, null, mSettingsIconId, mCodeSettings); null, null, mSettingsIconId, mCodeSettings);
assertParser("ICON with CODE", ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE,
null, null, mSettingsIconId, mCodeSettings);
}
public void testResourceReference() {
assertParser("Settings as more key", "!label/settings_as_more_key",
null, null, mSettingsIconId, mCodeSettings);
assertParser("SETTINGS AS MORE KEY", "!LABEL/SETTINGS_AS_MORE_KEY",
null, null, mSettingsIconId, mCodeSettings);
assertParser("Action next as more key", "!label/label_next_key|!code/key_action_next",
"Next", null, ICON_UNDEFINED, mCodeActionNext);
assertParser("ACTION NEXT AS MORE KEY", "!LABEL/LABEL_NEXT_KEY|!CODE/KEY_ACTION_NEXT",
"Next", null, ICON_UNDEFINED, mCodeActionNext);
assertParser("Popular domain",
"!label/keylabel_for_popular_domain|!label/keylabel_for_popular_domain ",
".com", ".com ", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParser("POPULAR DOMAIN",
"!LABEL/KEYLABEL_FOR_POPULAR_DOMAIN|!LABEL/KEYLABEL_FOR_POPULAR_DOMAIN ",
".com", ".com ", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
} }
public void testFormatError() { public void testFormatError() {
assertParserError("Empty spec", "", null, assertParserError("Empty spec", "", null,
null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); null, ICON_UNDEFINED, CODE_UNSPECIFIED);
assertParserError("Empty label with outputText", "|a", assertParserError("Empty label with outputText", "|a",
null, "a", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); null, "a", ICON_UNDEFINED, CODE_UNSPECIFIED);
assertParserError("Empty label with code", "|" + CODE_SETTINGS, assertParserError("Empty label with code", "|" + CODE_SETTINGS,
null, null, ICON_UNDEFINED, mCodeSettings); null, null, ICON_UNDEFINED, mCodeSettings);
assertParserError("Empty label with CODE", "|" + CODE_SETTINGS_UPPERCASE,
null, null, ICON_UNDEFINED, mCodeSettings);
assertParserError("Empty outputText with label", "a|", assertParserError("Empty outputText with label", "a|",
"a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", assertParserError("Empty outputText with icon", ICON_SETTINGS + "|",
null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED); null, null, mSettingsIconId, CODE_UNSPECIFIED);
assertParserError("Empty outputText with ICON", ICON_SETTINGS_UPPERCASE + "|",
null, null, mSettingsIconId, CODE_UNSPECIFIED);
assertParserError("Empty icon and code", "|", assertParserError("Empty icon and code", "|",
null, null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); null, null, ICON_UNDEFINED, CODE_UNSPECIFIED);
assertParserError("Icon without code", ICON_SETTINGS, assertParserError("Icon without code", ICON_SETTINGS,
null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED); null, null, mSettingsIconId, CODE_UNSPECIFIED);
assertParserError("ICON without code", ICON_SETTINGS_UPPERCASE,
null, null, mSettingsIconId, CODE_UNSPECIFIED);
assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc", assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc",
null, "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); null, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT);
assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING,
"abc", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); "abc", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
assertParserError("Third bar at end", "a|b|", assertParserError("Third bar at end", "a|b|",
"a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
assertParserError("Multiple bar", "a|b|c", assertParserError("Multiple bar", "a|b|c",
"a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED);
assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c", assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c",
"a", null, ICON_UNDEFINED, mCodeSettings); "a", null, ICON_UNDEFINED, mCodeSettings);
assertParserError("Multiple bar with label and CODE", "a|" + CODE_SETTINGS_UPPERCASE + "|c",
"a", null, ICON_UNDEFINED, mCodeSettings);
assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c", assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c",
null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED); null, null, mSettingsIconId, CODE_UNSPECIFIED);
assertParserError("Multiple bar with ICON and outputText", ICON_SETTINGS_UPPERCASE + "|b|c",
null, null, mSettingsIconId, CODE_UNSPECIFIED);
assertParserError("Multiple bar with icon and code", assertParserError("Multiple bar with icon and code",
ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", ICON_SETTINGS + "|" + CODE_SETTINGS + "|c",
null, null, mSettingsIconId, mCodeSettings); null, null, mSettingsIconId, mCodeSettings);
assertParserError("Multiple bar with ICON and CODE",
ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE + "|c",
null, null, mSettingsIconId, mCodeSettings);
} }
private static void assertMoreKeys(String message, String[] moreKeys, private static void assertArrayEquals(String message, Object[] expected, Object[] actual) {
String[] additionalMoreKeys, String[] expected) { if (expected == actual) {
final String[] actual = KeySpecParser.insertAdditionalMoreKeys(
moreKeys, additionalMoreKeys);
if (expected == null && actual == null) {
return; return;
} }
if (expected == null || actual == null) { if (expected == null || actual == null) {
assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); assertEquals(message, Arrays.toString(expected), Arrays.toString(actual));
} else { return;
if (expected.length != actual.length) { }
assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); if (expected.length != actual.length) {
} assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual));
for (int i = 0; i < expected.length; i++) { return;
if (!actual[i].equals(expected[i])) { }
assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); for (int i = 0; i < expected.length; i++) {
} assertEquals(message + " [" + i + "]",
} Arrays.toString(expected), Arrays.toString(actual));
} }
} }
private static void assertInsertAdditionalMoreKeys(String message, String[] moreKeys,
String[] additionalMoreKeys, String[] expected) {
final String[] actual =
KeySpecParser.insertAdditionalMoreKeys( moreKeys, additionalMoreKeys);
assertArrayEquals(message, expected, actual);
}
public void testEmptyEntry() { public void testEmptyEntry() {
assertMoreKeys("null more keys and null additons", assertInsertAdditionalMoreKeys("null more keys and null additons",
null, null,
null, null,
null); null);
assertMoreKeys("null more keys and empty additons", assertInsertAdditionalMoreKeys("null more keys and empty additons",
null, null,
new String[0], new String[0],
null); null);
assertMoreKeys("empty more keys and null additons", assertInsertAdditionalMoreKeys("empty more keys and null additons",
new String[0], new String[0],
null, null,
null); null);
assertMoreKeys("empty more keys and empty additons", assertInsertAdditionalMoreKeys("empty more keys and empty additons",
new String[0], new String[0],
new String[0], new String[0],
null); null);
assertMoreKeys("filter out empty more keys", assertInsertAdditionalMoreKeys("filter out empty more keys",
new String[] { null, "a", "", "b", null }, new String[] { null, "a", "", "b", null },
null, null,
new String[] { "a", "b" }); new String[] { "a", "b" });
assertMoreKeys("filter out empty additons", assertInsertAdditionalMoreKeys("filter out empty additons",
new String[] { "a", "%", "b", "%", "c", "%", "d" }, new String[] { "a", "%", "b", "%", "c", "%", "d" },
new String[] { null, "A", "", "B", null }, new String[] { null, "A", "", "B", null },
new String[] { "a", "A", "b", "B", "c", "d" }); new String[] { "a", "A", "b", "B", "c", "d" });
@ -302,188 +371,261 @@ public class KeySpecParserTests extends AndroidTestCase {
public void testInsertAdditionalMoreKeys() { public void testInsertAdditionalMoreKeys() {
// Escaped marker. // Escaped marker.
assertMoreKeys("escaped marker", assertInsertAdditionalMoreKeys("escaped marker",
new String[] { "\\%", "%-)" }, new String[] { "\\%", "%-)" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "2", "\\%", "%-)" }); new String[] { "1", "2", "\\%", "%-)" });
// 0 more key. // 0 more key.
assertMoreKeys("null & null", null, null, null); assertInsertAdditionalMoreKeys("null & null", null, null, null);
assertMoreKeys("null & 1 additon", assertInsertAdditionalMoreKeys("null & 1 additon",
null, null,
new String[] { "1" }, new String[] { "1" },
new String[] { "1" }); new String[] { "1" });
assertMoreKeys("null & 2 additons", assertInsertAdditionalMoreKeys("null & 2 additons",
null, null,
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "2" }); new String[] { "1", "2" });
// 0 additional more key. // 0 additional more key.
assertMoreKeys("1 more key & null", assertInsertAdditionalMoreKeys("1 more key & null",
new String[] { "A" }, new String[] { "A" },
null, null,
new String[] { "A" }); new String[] { "A" });
assertMoreKeys("2 more keys & null", assertInsertAdditionalMoreKeys("2 more keys & null",
new String[] { "A", "B" }, new String[] { "A", "B" },
null, null,
new String[] { "A", "B" }); new String[] { "A", "B" });
// No marker. // No marker.
assertMoreKeys("1 more key & 1 addtional & no marker", assertInsertAdditionalMoreKeys("1 more key & 1 addtional & no marker",
new String[] { "A" }, new String[] { "A" },
new String[] { "1" }, new String[] { "1" },
new String[] { "1", "A" }); new String[] { "1", "A" });
assertMoreKeys("1 more key & 2 addtionals & no marker", assertInsertAdditionalMoreKeys("1 more key & 2 addtionals & no marker",
new String[] { "A" }, new String[] { "A" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "2", "A" }); new String[] { "1", "2", "A" });
assertMoreKeys("2 more keys & 1 addtional & no marker", assertInsertAdditionalMoreKeys("2 more keys & 1 addtional & no marker",
new String[] { "A", "B" }, new String[] { "A", "B" },
new String[] { "1" }, new String[] { "1" },
new String[] { "1", "A", "B" }); new String[] { "1", "A", "B" });
assertMoreKeys("2 more keys & 2 addtionals & no marker", assertInsertAdditionalMoreKeys("2 more keys & 2 addtionals & no marker",
new String[] { "A", "B" }, new String[] { "A", "B" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "2", "A", "B" }); new String[] { "1", "2", "A", "B" });
// 1 marker. // 1 marker.
assertMoreKeys("1 more key & 1 additon & marker at head", assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at head",
new String[] { "%", "A" }, new String[] { "%", "A" },
new String[] { "1" }, new String[] { "1" },
new String[] { "1", "A" }); new String[] { "1", "A" });
assertMoreKeys("1 more key & 1 additon & marker at tail", assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at tail",
new String[] { "A", "%" }, new String[] { "A", "%" },
new String[] { "1" }, new String[] { "1" },
new String[] { "A", "1" }); new String[] { "A", "1" });
assertMoreKeys("2 more keys & 1 additon & marker at middle", assertInsertAdditionalMoreKeys("2 more keys & 1 additon & marker at middle",
new String[] { "A", "%", "B" }, new String[] { "A", "%", "B" },
new String[] { "1" }, new String[] { "1" },
new String[] { "A", "1", "B" }); new String[] { "A", "1", "B" });
// 1 marker & excess additional more keys. // 1 marker & excess additional more keys.
assertMoreKeys("1 more key & 2 additons & marker at head", assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at head",
new String[] { "%", "A", "B" }, new String[] { "%", "A", "B" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "A", "B", "2" }); new String[] { "1", "A", "B", "2" });
assertMoreKeys("1 more key & 2 additons & marker at tail", assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at tail",
new String[] { "A", "B", "%" }, new String[] { "A", "B", "%" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "A", "B", "1", "2" }); new String[] { "A", "B", "1", "2" });
assertMoreKeys("2 more keys & 2 additons & marker at middle", assertInsertAdditionalMoreKeys("2 more keys & 2 additons & marker at middle",
new String[] { "A", "%", "B" }, new String[] { "A", "%", "B" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "A", "1", "B", "2" }); new String[] { "A", "1", "B", "2" });
// 2 markers. // 2 markers.
assertMoreKeys("0 more key & 2 addtional & 2 markers", assertInsertAdditionalMoreKeys("0 more key & 2 addtional & 2 markers",
new String[] { "%", "%" }, new String[] { "%", "%" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "2" }); new String[] { "1", "2" });
assertMoreKeys("1 more key & 2 addtional & 2 markers at head", assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at head",
new String[] { "%", "%", "A" }, new String[] { "%", "%", "A" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "2", "A" }); new String[] { "1", "2", "A" });
assertMoreKeys("1 more key & 2 addtional & 2 markers at tail", assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at tail",
new String[] { "A", "%", "%" }, new String[] { "A", "%", "%" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "A", "1", "2" }); new String[] { "A", "1", "2" });
assertMoreKeys("2 more keys & 2 addtional & 2 markers at middle", assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle",
new String[] { "A", "%", "%", "B" }, new String[] { "A", "%", "%", "B" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "A", "1", "2", "B" }); new String[] { "A", "1", "2", "B" });
assertMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle", assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle",
new String[] { "%", "A", "%", "B" }, new String[] { "%", "A", "%", "B" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "A", "2", "B" }); new String[] { "1", "A", "2", "B" });
assertMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail", assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail",
new String[] { "%", "A", "B", "%" }, new String[] { "%", "A", "B", "%" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "A", "B", "2" }); new String[] { "1", "A", "B", "2" });
assertMoreKeys("2 more keys & 2 addtional & 2 markers at middle & tail", assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle & tail",
new String[] { "A", "%", "B", "%" }, new String[] { "A", "%", "B", "%" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "A", "1", "B", "2" }); new String[] { "A", "1", "B", "2" });
// 2 markers & excess additional more keys. // 2 markers & excess additional more keys.
assertMoreKeys("0 more key & 2 additons & 2 markers", assertInsertAdditionalMoreKeys("0 more key & 2 additons & 2 markers",
new String[] { "%", "%" }, new String[] { "%", "%" },
new String[] { "1", "2", "3" }, new String[] { "1", "2", "3" },
new String[] { "1", "2", "3" }); new String[] { "1", "2", "3" });
assertMoreKeys("1 more key & 2 additons & 2 markers at head", assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at head",
new String[] { "%", "%", "A" }, new String[] { "%", "%", "A" },
new String[] { "1", "2", "3" }, new String[] { "1", "2", "3" },
new String[] { "1", "2", "A", "3" }); new String[] { "1", "2", "A", "3" });
assertMoreKeys("1 more key & 2 additons & 2 markers at tail", assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at tail",
new String[] { "A", "%", "%" }, new String[] { "A", "%", "%" },
new String[] { "1", "2", "3" }, new String[] { "1", "2", "3" },
new String[] { "A", "1", "2", "3" }); new String[] { "A", "1", "2", "3" });
assertMoreKeys("2 more keys & 2 additons & 2 markers at middle", assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle",
new String[] { "A", "%", "%", "B" }, new String[] { "A", "%", "%", "B" },
new String[] { "1", "2", "3" }, new String[] { "1", "2", "3" },
new String[] { "A", "1", "2", "B", "3" }); new String[] { "A", "1", "2", "B", "3" });
assertMoreKeys("2 more keys & 2 additons & 2 markers at head & middle", assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & middle",
new String[] { "%", "A", "%", "B" }, new String[] { "%", "A", "%", "B" },
new String[] { "1", "2", "3" }, new String[] { "1", "2", "3" },
new String[] { "1", "A", "2", "B", "3" }); new String[] { "1", "A", "2", "B", "3" });
assertMoreKeys("2 more keys & 2 additons & 2 markers at head & tail", assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & tail",
new String[] { "%", "A", "B", "%" }, new String[] { "%", "A", "B", "%" },
new String[] { "1", "2", "3" }, new String[] { "1", "2", "3" },
new String[] { "1", "A", "B", "2", "3" }); new String[] { "1", "A", "B", "2", "3" });
assertMoreKeys("2 more keys & 2 additons & 2 markers at middle & tail", assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle & tail",
new String[] { "A", "%", "B", "%" }, new String[] { "A", "%", "B", "%" },
new String[] { "1", "2", "3" }, new String[] { "1", "2", "3" },
new String[] { "A", "1", "B", "2", "3" }); new String[] { "A", "1", "B", "2", "3" });
// 0 addtional more key and excess markers. // 0 addtional more key and excess markers.
assertMoreKeys("0 more key & null & excess marker", assertInsertAdditionalMoreKeys("0 more key & null & excess marker",
new String[] { "%" }, new String[] { "%" },
null, null,
null); null);
assertMoreKeys("1 more key & null & excess marker at head", assertInsertAdditionalMoreKeys("1 more key & null & excess marker at head",
new String[] { "%", "A" }, new String[] { "%", "A" },
null, null,
new String[] { "A" }); new String[] { "A" });
assertMoreKeys("1 more key & null & excess marker at tail", assertInsertAdditionalMoreKeys("1 more key & null & excess marker at tail",
new String[] { "A", "%" }, new String[] { "A", "%" },
null, null,
new String[] { "A" }); new String[] { "A" });
assertMoreKeys("2 more keys & null & excess marker at middle", assertInsertAdditionalMoreKeys("2 more keys & null & excess marker at middle",
new String[] { "A", "%", "B" }, new String[] { "A", "%", "B" },
null, null,
new String[] { "A", "B" }); new String[] { "A", "B" });
assertMoreKeys("2 more keys & null & excess markers", assertInsertAdditionalMoreKeys("2 more keys & null & excess markers",
new String[] { "%", "A", "%", "B", "%" }, new String[] { "%", "A", "%", "B", "%" },
null, null,
new String[] { "A", "B" }); new String[] { "A", "B" });
// Excess markers. // Excess markers.
assertMoreKeys("0 more key & 1 additon & excess marker", assertInsertAdditionalMoreKeys("0 more key & 1 additon & excess marker",
new String[] { "%", "%" }, new String[] { "%", "%" },
new String[] { "1" }, new String[] { "1" },
new String[] { "1" }); new String[] { "1" });
assertMoreKeys("1 more key & 1 additon & excess marker at head", assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at head",
new String[] { "%", "%", "A" }, new String[] { "%", "%", "A" },
new String[] { "1" }, new String[] { "1" },
new String[] { "1", "A" }); new String[] { "1", "A" });
assertMoreKeys("1 more key & 1 additon & excess marker at tail", assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at tail",
new String[] { "A", "%", "%" }, new String[] { "A", "%", "%" },
new String[] { "1" }, new String[] { "1" },
new String[] { "A", "1" }); new String[] { "A", "1" });
assertMoreKeys("2 more keys & 1 additon & excess marker at middle", assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess marker at middle",
new String[] { "A", "%", "%", "B" }, new String[] { "A", "%", "%", "B" },
new String[] { "1" }, new String[] { "1" },
new String[] { "A", "1", "B" }); new String[] { "A", "1", "B" });
assertMoreKeys("2 more keys & 1 additon & excess markers", assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess markers",
new String[] { "%", "A", "%", "B", "%" }, new String[] { "%", "A", "%", "B", "%" },
new String[] { "1" }, new String[] { "1" },
new String[] { "1", "A", "B" }); new String[] { "1", "A", "B" });
assertMoreKeys("2 more keys & 2 additons & excess markers", assertInsertAdditionalMoreKeys("2 more keys & 2 additons & excess markers",
new String[] { "%", "A", "%", "B", "%" }, new String[] { "%", "A", "%", "B", "%" },
new String[] { "1", "2" }, new String[] { "1", "2" },
new String[] { "1", "A", "2", "B" }); new String[] { "1", "A", "2", "B" });
assertMoreKeys("2 more keys & 3 additons & excess markers", assertInsertAdditionalMoreKeys("2 more keys & 3 additons & excess markers",
new String[] { "%", "A", "%", "%", "B", "%" }, new String[] { "%", "A", "%", "%", "B", "%" },
new String[] { "1", "2", "3" }, new String[] { "1", "2", "3" },
new String[] { "1", "A", "2", "3", "B" }); new String[] { "1", "A", "2", "3", "B" });
} }
private static final String HAS_LABEL = "!hasLabel!";
private static final String NEEDS_DIVIDER = "!needsDividers!";
private static final String AUTO_COLUMN_ORDER = "!autoColumnOrder!";
private static final String FIXED_COLUMN_ORDER = "!fixedColumnOrder!";
private static void assertGetBooleanValue(String message, String key, String[] moreKeys,
String[] expected, boolean expectedValue) {
final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length);
final boolean actualValue = KeySpecParser.getBooleanValue(actual, key);
assertEquals(message + " [value]", expectedValue, actualValue);
assertArrayEquals(message, expected, actual);
}
public void testGetBooleanValue() {
assertGetBooleanValue("Has label", HAS_LABEL,
new String[] { HAS_LABEL, "a", "b", "c" },
new String[] { null, "a", "b", "c" }, true);
assertGetBooleanValue("HAS LABEL", HAS_LABEL,
new String[] { HAS_LABEL.toUpperCase(), "a", "b", "c" },
new String[] { null, "a", "b", "c" }, true);
assertGetBooleanValue("No has label", HAS_LABEL,
new String[] { "a", "b", "c" },
new String[] { "a", "b", "c" }, false);
assertGetBooleanValue("No has label with fixed clumn order", HAS_LABEL,
new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" },
new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, false);
assertGetBooleanValue("Multiple has label", HAS_LABEL,
new String[] {
"a", HAS_LABEL.toUpperCase(), "b", "c", HAS_LABEL, "d" },
new String[] {
"a", null, "b", "c", null, "d" }, true);
assertGetBooleanValue("Multiple has label with needs dividers", HAS_LABEL,
new String[] {
"a", HAS_LABEL, "b", NEEDS_DIVIDER, HAS_LABEL.toUpperCase(), "d" },
new String[] {
"a", null, "b", NEEDS_DIVIDER, null, "d" }, true);
}
private static void assertGetIntValue(String message, String key, int defaultValue,
String[] moreKeys, String[] expected, int expectedValue) {
final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length);
final int actualValue = KeySpecParser.getIntValue(actual, key, defaultValue);
assertEquals(message + " [value]", expectedValue, actualValue);
assertArrayEquals(message, expected, actual);
}
public void testGetIntValue() {
assertGetIntValue("Fixed column order 3", FIXED_COLUMN_ORDER, -1,
new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" },
new String[] { null, "a", "b", "c" }, 3);
assertGetIntValue("FIXED COLUMN ORDER 3", FIXED_COLUMN_ORDER, -1,
new String[] { FIXED_COLUMN_ORDER.toUpperCase() + "3", "a", "b", "c" },
new String[] { null, "a", "b", "c" }, 3);
assertGetIntValue("No fixed column order", FIXED_COLUMN_ORDER, -1,
new String[] { "a", "b", "c" },
new String[] { "a", "b", "c" }, -1);
assertGetIntValue("No fixed column order with auto column order", FIXED_COLUMN_ORDER, -1,
new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" },
new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, -1);
assertGetIntValue("Multiple fixed column order 3,5", FIXED_COLUMN_ORDER, -1,
new String[] { FIXED_COLUMN_ORDER + "3", "a", FIXED_COLUMN_ORDER + "5", "b" },
new String[] { null, "a", null, "b" }, 3);
assertGetIntValue("Multiple fixed column order 5,3 with has label", FIXED_COLUMN_ORDER, -1,
new String[] {
FIXED_COLUMN_ORDER.toUpperCase() + "5", HAS_LABEL, "a",
FIXED_COLUMN_ORDER + "3", "b" },
new String[] { null, HAS_LABEL, "a", null, "b" }, 5);
}
} }

View File

@ -31,7 +31,8 @@ public final class KeyboardLabelsSet {
// Language to labels map. // Language to labels map.
private static final HashMap<String, String[]> sLocaleToLabelsMap = private static final HashMap<String, String[]> sLocaleToLabelsMap =
new HashMap<String, String[]>(); new HashMap<String, String[]>();
private static final HashMap<String, Integer> sNameToIdMap = new HashMap<String, Integer>(); private static final HashMap<String, Integer> sLowerCaseNameToIdsMap =
new HashMap<String, Integer>();
private String[] mLabels; private String[] mLabels;
// Resource name to label map. // Resource name to label map.
@ -60,12 +61,21 @@ public final class KeyboardLabelsSet {
} }
public String getLabel(final String name) { public String getLabel(final String name) {
if (mResourceNameToLabelsMap.containsKey(name)) { String lowerCaseName = null;
return mResourceNameToLabelsMap.get(name); String label = mResourceNameToLabelsMap.get(name);
if (label == null) {
lowerCaseName = name.toLowerCase();
label = mResourceNameToLabelsMap.get(lowerCaseName);
}
if (label != null) {
return label;
}
Integer id = sLowerCaseNameToIdsMap.get(name);
if (id == null) {
id = sLowerCaseNameToIdsMap.get(lowerCaseName); // lowerCaseName != null
} }
final Integer id = sNameToIdMap.get(name);
if (id == null) throw new RuntimeException("Unknown label: " + name); if (id == null) throw new RuntimeException("Unknown label: " + name);
final String label = (id < mLabels.length) ? mLabels[id] : null; label = (id < mLabels.length) ? mLabels[id] : null;
return (label == null) ? LANGUAGE_DEFAULT[id] : label; return (label == null) ? LANGUAGE_DEFAULT[id] : label;
} }
@ -105,7 +115,7 @@ public final class KeyboardLabelsSet {
static { static {
int id = 0; int id = 0;
for (final String name : NAMES) { for (final String name : NAMES) {
sNameToIdMap.put(name, id++); sLowerCaseNameToIdsMap.put(name, id++);
} }
for (int i = 0; i < LANGUAGES_AND_LABELS.length; i += 2) { for (int i = 0; i < LANGUAGES_AND_LABELS.length; i += 2) {