diff options
Diffstat (limited to 'java/src')
17 files changed, 1172 insertions, 649 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index b7eb8f69c..233716acf 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -16,6 +16,8 @@ package com.android.inputmethod.keyboard; +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; + import android.text.InputType; import android.text.TextUtils; import android.view.inputmethod.EditorInfo; @@ -23,7 +25,6 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.latin.InputTypeUtils; -import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.SubtypeLocale; import java.util.Arrays; @@ -184,7 +185,7 @@ public class KeyboardId { return String.format("[%s %s:%s %s%d %s %s %s%s%s%s%s%s%s%s]", elementIdToName(mElementId), mLocale, - mSubtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET), + mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), (mOrientation == 1 ? "port" : "land"), mWidth, modeName(mMode), imeAction(), diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java index 35209e0ad..8c7246855 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java @@ -16,6 +16,12 @@ package com.android.inputmethod.keyboard; +import static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII; +import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE; +import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT; +import static com.android.inputmethod.latin.Constants.ImeOption.NO_SETTINGS_KEY; +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.ASCII_CAPABLE; + import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -29,11 +35,10 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.keyboard.KeyboardLayoutSet.Params.ElementParams; +import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.InputTypeUtils; -import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SubtypeLocale; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.XmlParseUtils; @@ -229,8 +234,8 @@ public class KeyboardLayoutSet { params.mMode = getKeyboardMode(editorInfo); params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO; - params.mNoSettingsKey = StringUtils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo); + params.mNoSettingsKey = InputAttributes.inPrivateImeOptions( + mPackageName, NO_SETTINGS_KEY, mEditorInfo); } public Builder setScreenGeometry(int orientation, int widthPixels) { @@ -240,10 +245,10 @@ public class KeyboardLayoutSet { } public Builder setSubtype(InputMethodSubtype subtype) { - final boolean asciiCapable = subtype.containsExtraValueKey( - LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE); - final boolean deprecatedForceAscii = StringUtils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); + final boolean asciiCapable = subtype.containsExtraValueKey(ASCII_CAPABLE); + @SuppressWarnings("deprecation") + final boolean deprecatedForceAscii = InputAttributes.inPrivateImeOptions( + mPackageName, FORCE_ASCII, mEditorInfo); final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( mParams.mEditorInfo.imeOptions) || deprecatedForceAscii; @@ -259,10 +264,10 @@ public class KeyboardLayoutSet { public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain, boolean languageSwitchKeyEnabled) { @SuppressWarnings("deprecation") - final boolean deprecatedNoMicrophone = StringUtils.inPrivateImeOptions( - null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); - final boolean noMicrophone = StringUtils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo) + final boolean deprecatedNoMicrophone = InputAttributes.inPrivateImeOptions( + null, NO_MICROPHONE_COMPAT, mEditorInfo); + final boolean noMicrophone = InputAttributes.inPrivateImeOptions( + mPackageName, NO_MICROPHONE, mEditorInfo) || deprecatedNoMicrophone; mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; mParams.mVoiceKeyOnMain = voiceKeyOnMain; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java index 9bbd3a280..8261400b2 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -159,7 +159,7 @@ public class KeySpecParser { return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1)); } - private static String getOutputText(String moreKeySpec) { + static String getOutputText(String moreKeySpec) { if (hasCode(moreKeySpec)) { return null; } @@ -183,7 +183,7 @@ public class KeySpecParser { return (StringUtils.codePointCount(label) == 1) ? null : label; } - private static int getCode(String moreKeySpec, KeyboardCodesSet codesSet) { + static int getCode(String moreKeySpec, KeyboardCodesSet codesSet) { if (hasCode(moreKeySpec)) { final int end = indexOfLabelEnd(moreKeySpec, 0); if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { @@ -219,7 +219,7 @@ public class KeySpecParser { } } - private static int getIconId(String moreKeySpec) { + static int getIconId(String moreKeySpec) { if (hasIcon(moreKeySpec)) { final int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length()); final String name = moreKeySpec.substring(PREFIX_ICON.length(), end); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java index a46f3bf1b..0518b07ff 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java @@ -138,75 +138,76 @@ public final class KeyboardLabelsSet { /* 48 */ "more_keys_for_smiley", /* 49 */ "more_keys_for_punctuation", /* 50 */ "keyhintlabel_for_punctuation", - /* 51 */ "keylabel_for_popular_domain", - /* 52 */ "more_keys_for_popular_domain", - /* 53 */ "keylabel_for_symbols_1", - /* 54 */ "keylabel_for_symbols_2", - /* 55 */ "keylabel_for_symbols_3", - /* 56 */ "keylabel_for_symbols_4", - /* 57 */ "keylabel_for_symbols_5", - /* 58 */ "keylabel_for_symbols_6", - /* 59 */ "keylabel_for_symbols_7", - /* 60 */ "keylabel_for_symbols_8", - /* 61 */ "keylabel_for_symbols_9", - /* 62 */ "keylabel_for_symbols_0", - /* 63 */ "additional_more_keys_for_symbols_1", - /* 64 */ "additional_more_keys_for_symbols_2", - /* 65 */ "additional_more_keys_for_symbols_3", - /* 66 */ "additional_more_keys_for_symbols_4", - /* 67 */ "additional_more_keys_for_symbols_5", - /* 68 */ "additional_more_keys_for_symbols_6", - /* 69 */ "additional_more_keys_for_symbols_7", - /* 70 */ "additional_more_keys_for_symbols_8", - /* 71 */ "additional_more_keys_for_symbols_9", - /* 72 */ "additional_more_keys_for_symbols_0", - /* 73 */ "more_keys_for_symbols_1", - /* 74 */ "more_keys_for_symbols_2", - /* 75 */ "more_keys_for_symbols_3", - /* 76 */ "more_keys_for_symbols_4", - /* 77 */ "more_keys_for_symbols_5", - /* 78 */ "more_keys_for_symbols_6", - /* 79 */ "more_keys_for_symbols_7", - /* 80 */ "more_keys_for_symbols_8", - /* 81 */ "more_keys_for_symbols_9", - /* 82 */ "more_keys_for_symbols_0", - /* 83 */ "more_keys_for_am_pm", - /* 84 */ "settings_as_more_key", - /* 85 */ "keylabel_for_comma", - /* 86 */ "more_keys_for_comma", - /* 87 */ "action_next_as_more_key", - /* 88 */ "action_previous_as_more_key", - /* 89 */ "keylabel_for_symbols_question", - /* 90 */ "keylabel_for_symbols_semicolon", - /* 91 */ "keylabel_for_symbols_percent", - /* 92 */ "more_keys_for_symbols_question", - /* 93 */ "more_keys_for_symbols_semicolon", - /* 94 */ "more_keys_for_symbols_percent", - /* 95 */ "keylabel_for_tablet_comma", - /* 96 */ "keyhintlabel_for_tablet_comma", - /* 97 */ "more_keys_for_tablet_comma", - /* 98 */ "keyhintlabel_for_tablet_period", - /* 99 */ "more_keys_for_tablet_period", - /* 100 */ "keylabel_for_apostrophe", - /* 101 */ "keylabel_for_dash", - /* 102 */ "keyhintlabel_for_apostrophe", - /* 103 */ "keyhintlabel_for_dash", - /* 104 */ "more_keys_for_apostrophe", - /* 105 */ "more_keys_for_dash", - /* 106 */ "more_keys_for_bullet", - /* 107 */ "more_keys_for_star", - /* 108 */ "more_keys_for_plus", - /* 109 */ "more_keys_for_left_parenthesis", - /* 110 */ "more_keys_for_right_parenthesis", - /* 111 */ "more_keys_for_less_than", - /* 112 */ "more_keys_for_greater_than", - /* 113 */ "label_to_more_symbol_key", - /* 114 */ "label_to_more_symbol_for_tablet_key", - /* 115 */ "label_tab_key", - /* 116 */ "label_to_phone_numeric_key", - /* 117 */ "label_to_phone_symbols_key", - /* 118 */ "label_time_am", - /* 119 */ "label_time_pm", + /* 51 */ "more_keys_for_star", + /* 52 */ "more_keys_for_plus", + /* 53 */ "more_keys_for_left_parenthesis", + /* 54 */ "more_keys_for_right_parenthesis", + /* 55 */ "more_keys_for_less_than", + /* 56 */ "more_keys_for_greater_than", + /* 57 */ "keylabel_for_popular_domain", + /* 58 */ "more_keys_for_popular_domain", + /* 59 */ "keylabel_for_symbols_1", + /* 60 */ "keylabel_for_symbols_2", + /* 61 */ "keylabel_for_symbols_3", + /* 62 */ "keylabel_for_symbols_4", + /* 63 */ "keylabel_for_symbols_5", + /* 64 */ "keylabel_for_symbols_6", + /* 65 */ "keylabel_for_symbols_7", + /* 66 */ "keylabel_for_symbols_8", + /* 67 */ "keylabel_for_symbols_9", + /* 68 */ "keylabel_for_symbols_0", + /* 69 */ "additional_more_keys_for_symbols_1", + /* 70 */ "additional_more_keys_for_symbols_2", + /* 71 */ "additional_more_keys_for_symbols_3", + /* 72 */ "additional_more_keys_for_symbols_4", + /* 73 */ "additional_more_keys_for_symbols_5", + /* 74 */ "additional_more_keys_for_symbols_6", + /* 75 */ "additional_more_keys_for_symbols_7", + /* 76 */ "additional_more_keys_for_symbols_8", + /* 77 */ "additional_more_keys_for_symbols_9", + /* 78 */ "additional_more_keys_for_symbols_0", + /* 79 */ "more_keys_for_symbols_1", + /* 80 */ "more_keys_for_symbols_2", + /* 81 */ "more_keys_for_symbols_3", + /* 82 */ "more_keys_for_symbols_4", + /* 83 */ "more_keys_for_symbols_5", + /* 84 */ "more_keys_for_symbols_6", + /* 85 */ "more_keys_for_symbols_7", + /* 86 */ "more_keys_for_symbols_8", + /* 87 */ "more_keys_for_symbols_9", + /* 88 */ "more_keys_for_symbols_0", + /* 89 */ "keylabel_for_comma", + /* 90 */ "more_keys_for_comma", + /* 91 */ "keylabel_for_symbols_question", + /* 92 */ "keylabel_for_symbols_semicolon", + /* 93 */ "keylabel_for_symbols_percent", + /* 94 */ "more_keys_for_symbols_question", + /* 95 */ "more_keys_for_symbols_semicolon", + /* 96 */ "more_keys_for_symbols_percent", + /* 97 */ "keylabel_for_tablet_comma", + /* 98 */ "keyhintlabel_for_tablet_comma", + /* 99 */ "more_keys_for_tablet_comma", + /* 100 */ "keyhintlabel_for_tablet_period", + /* 101 */ "more_keys_for_tablet_period", + /* 102 */ "keylabel_for_apostrophe", + /* 103 */ "keylabel_for_dash", + /* 104 */ "keyhintlabel_for_apostrophe", + /* 105 */ "keyhintlabel_for_dash", + /* 106 */ "more_keys_for_apostrophe", + /* 107 */ "more_keys_for_dash", + /* 108 */ "more_keys_for_bullet", + /* 109 */ "more_keys_for_am_pm", + /* 110 */ "settings_as_more_key", + /* 111 */ "shortcut_as_more_key", + /* 112 */ "action_next_as_more_key", + /* 113 */ "action_previous_as_more_key", + /* 114 */ "label_to_more_symbol_key", + /* 115 */ "label_to_more_symbol_for_tablet_key", + /* 116 */ "label_tab_key", + /* 117 */ "label_to_phone_numeric_key", + /* 118 */ "label_to_phone_symbols_key", + /* 119 */ "label_time_am", + /* 120 */ "label_time_pm", }; private static final String EMPTY = ""; @@ -220,9 +221,11 @@ public final class KeyboardLabelsSet { EMPTY, EMPTY, /* ~40 */ /* 41 */ "!fixedColumnOrder!4,\u2018,\u2019,\u201A,\u201B", - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. <string name="more_keys_for_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. + // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»</string> /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB", - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. + // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", // U+00A2: "¢" CENT SIGN // U+00A3: "£" POUND SIGN @@ -236,120 +239,122 @@ public final class KeyboardLabelsSet { /* 48 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ", /* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)", /* 50 */ EMPTY, - /* 51 */ ".com", + // U+2020: "†" DAGGER + // U+2021: "‡" DOUBLE DAGGER + // U+2605: "★" BLACK STAR + /* 51 */ "\u2020,\u2021,\u2605", + // U+00B1: "±" PLUS-MINUS SIGN + /* 52 */ "\u00B1", + // The all letters need to be mirrored are found at + // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt + /* 53 */ "!fixedColumnOrder!3,<,{,[", + /* 54 */ "!fixedColumnOrder!3,>,},]", + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // The following characters don't need BIDI mirroring. + // U+2018: "‘" LEFT SINGLE QUOTATION MARK + // U+2019: "’" RIGHT SINGLE QUOTATION MARK + // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK + // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK + // U+201C: "“" LEFT DOUBLE QUOTATION MARK + // U+201D: "”" RIGHT DOUBLE QUOTATION MARK + // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK + // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK + /* 55 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB", + /* 56 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB", + /* 57 */ ".com", // popular web domains for the locale - most popular, displayed on the keyboard - /* 52 */ "!hasLabels!,.net,.org,.gov,.edu", - /* 53 */ "1", - /* 54 */ "2", - /* 55 */ "3", - /* 56 */ "4", - /* 57 */ "5", - /* 58 */ "6", - /* 59 */ "7", - /* 60 */ "8", - /* 61 */ "9", - /* 62 */ "0", - /* 63~ */ + /* 58 */ "!hasLabels!,.net,.org,.gov,.edu", + /* 59 */ "1", + /* 60 */ "2", + /* 61 */ "3", + /* 62 */ "4", + /* 63 */ "5", + /* 64 */ "6", + /* 65 */ "7", + /* 66 */ "8", + /* 67 */ "9", + /* 68 */ "0", + /* 69~ */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - /* ~72 */ + /* ~78 */ // U+00B9: "¹" SUPERSCRIPT ONE // U+00BD: "½" VULGAR FRACTION ONE HALF // U+2153: "⅓" VULGAR FRACTION ONE THIRD // U+00BC: "¼" VULGAR FRACTION ONE QUARTER // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH - /* 73 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B", + /* 79 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B", // U+00B2: "²" SUPERSCRIPT TWO // U+2154: "⅔" VULGAR FRACTION TWO THIRDS - /* 74 */ "\u00B2,\u2154", + /* 80 */ "\u00B2,\u2154", // U+00B3: "³" SUPERSCRIPT THREE // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS - /* 75 */ "\u00B3,\u00BE,\u215C", + /* 81 */ "\u00B3,\u00BE,\u215C", // U+2074: "⁴" SUPERSCRIPT FOUR - /* 76 */ "\u2074", + /* 82 */ "\u2074", // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS - /* 77 */ "\u215D", - /* 78 */ EMPTY, + /* 83 */ "\u215D", + /* 84 */ EMPTY, // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS - /* 79 */ "\u215E", - /* 80 */ EMPTY, - /* 81 */ EMPTY, + /* 85 */ "\u215E", + /* 86 */ EMPTY, + /* 87 */ EMPTY, // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N // U+2205: "∅" EMPTY SET - /* 82 */ "\u207F,\u2205", - /* 83 */ "!fixedColumnOrder!2,!hasLabels!,!label/label_time_am,!label/label_time_pm", - /* 84 */ "!icon/settingsKey|!code/key_settings", - /* 85 */ ",", - /* 86 */ EMPTY, - /* 87 */ "!hasLabels!,!label/label_next_key|!code/key_action_next", - /* 88 */ "!hasLabels!,!label/label_previous_key|!code/key_action_previous", - /* 89 */ "?", - /* 90 */ ";", - /* 91 */ "%", + /* 88 */ "\u207F,\u2205", + /* 89 */ ",", + /* 90 */ EMPTY, + /* 91 */ "?", + /* 92 */ ";", + /* 93 */ "%", // U+00BF: "¿" INVERTED QUESTION MARK - /* 92 */ "\u00BF", - /* 93 */ EMPTY, + /* 94 */ "\u00BF", + /* 95 */ EMPTY, // U+2030: "‰" PER MILLE SIGN - /* 94 */ "\u2030", - /* 95 */ ",", - /* 96 */ "!", - /* 97 */ "!", - /* 98 */ "?", - /* 99 */ "?", - /* 100 */ "\'", - /* 101 */ "-", - /* 102 */ "\"", - /* 103 */ "_", + /* 96 */ "\u2030", + /* 97 */ ",", + /* 98 */ "!", + /* 99 */ "!", + /* 100 */ "?", + /* 101 */ "?", + /* 102 */ "\'", + /* 103 */ "-", /* 104 */ "\"", /* 105 */ "_", + /* 106 */ "\"", + /* 107 */ "_", // U+266A: "♪" EIGHTH NOTE // U+2665: "♥" BLACK HEART SUIT // U+2660: "♠" BLACK SPADE SUIT // U+2666: "♦" BLACK DIAMOND SUIT // U+2663: "♣" BLACK CLUB SUIT - /* 106 */ "\u266A,\u2665,\u2660,\u2666,\u2663", - // U+2020: "†" DAGGER - // U+2021: "‡" DOUBLE DAGGER - // U+2605: "★" BLACK STAR - /* 107 */ "\u2020,\u2021,\u2605", - // U+00B1: "±" PLUS-MINUS SIGN - /* 108 */ "\u00B1", - // The all letters need to be mirrored are found at - // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt - /* 109 */ "!fixedColumnOrder!3,<,{,[", - /* 110 */ "!fixedColumnOrder!3,>,},]", - // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - // U+2264: "≤" LESS-THAN OR EQUAL TO - // U+2265: "≥" GREATER-THAN EQUAL TO - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - // The following characters don't need BIDI mirroring. - // U+2018: "‘" LEFT SINGLE QUOTATION MARK - // U+2019: "’" RIGHT SINGLE QUOTATION MARK - // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK - // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK - // U+201C: "“" LEFT DOUBLE QUOTATION MARK - // U+201D: "”" RIGHT DOUBLE QUOTATION MARK - // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK - // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - /* 111 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB", - /* 112 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB", + /* 108 */ "\u266A,\u2665,\u2660,\u2666,\u2663", + /* 109 */ "!fixedColumnOrder!2,!hasLabels!,!label/label_time_am,!label/label_time_pm", + /* 110 */ "!icon/settingsKey|!code/key_settings", + /* 111 */ "!icon/shortcutKey|!code/key_shortcut", + /* 112 */ "!hasLabels!,!label/label_next_key|!code/key_action_next", + /* 113 */ "!hasLabels!,!label/label_previous_key|!code/key_action_previous", // Label for "switch to more symbol" modifier key. Must be short to fit on key! - /* 113 */ "= \\ <", + /* 114 */ "= \\ <", // Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key! - /* 114 */ "~ \\ {", + /* 115 */ "~ \\ {", // Label for "Tab" key. Must be short to fit on key! - /* 115 */ "Tab", + /* 116 */ "Tab", // Label for "switch to phone numeric" key. Must be short to fit on key! - /* 116 */ "123", - // Label for "switch to phone symbols" key. Must be short to fit on key! U+FF0A: "*" FULLWIDTH ASTERISK + /* 117 */ "123", + // Label for "switch to phone symbols" key. Must be short to fit on key! + // U+FF0A: "*" FULLWIDTH ASTERISK // U+FF03: "#" FULLWIDTH NUMBER SIGN - /* 117 */ "\uFF0A\uFF03", + /* 118 */ "\uFF0A\uFF03", // Key label for "ante meridiem" - /* 118 */ "AM", + /* 119 */ "AM", // Key label for "post meridiem" - /* 119 */ "PM", + /* 120 */ "PM", }; /* Language ar: Arabic */ @@ -359,132 +364,141 @@ public final class KeyboardLabelsSet { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, /* ~41 */ - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK + // <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB", - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK + // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", /* 44~ */ null, null, null, null, null, /* ~48 */ // U+061F: "؟" ARABIC QUESTION MARK // U+060C: "،" ARABIC COMMA - // U+061B: "؛" ARABIC SEMICOLON U+0650: "ِ" ARABIC KASRA + // U+061B: "؛" ARABIC SEMICOLON + // U+0650: "ِ" ARABIC KASRA // U+064E: "َ" ARABIC FATHA // U+064D: "ٍ" ARABIC KASRATAN // U+064B: "ً" ARABIC FATHATAN // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF // U+0655: "ٕ" ARABIC HAMZA BELOW - // U+0654: "ٔ" ARABIC HAMZA ABOVE U+064F: "ُ" ARABIC DAMMA + // U+0654: "ٔ" ARABIC HAMZA ABOVE + // U+064F: "ُ" ARABIC DAMMA // U+064C: "ٌ" ARABIC DAMMATAN // U+0651: "ّ" ARABIC SHADDA // U+0652: "ْ" ARABIC SUKUN // U+0653: "ٓ" ARABIC MADDAH ABOVE - // U+0640: "ـ" ARABIC TATWEEL In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. + // U+0640: "ـ" ARABIC TATWEEL + // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. /* 49 */ "!fixedColumnOrder!8,\",\',-,:,!,\u061F,\u060C,\u061B,\u0650,\u064E,\u064D,\u064B,\u0656,\u0670,\u0655,\u0654,\u064F,\u064C,\u0651,\u0652,\u0653,\u0640\u0640\u0640|\u0640,/", /* 50 */ "\u064B", - /* 51 */ null, + // U+2605: "★" BLACK STAR + // U+066D: "٭" ARABIC FIVE POINTED STAR + /* 51 */ "\u2605,\u066D", /* 52 */ null, + // The all letters need to be mirrored are found at + // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt + // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS + // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS + // TODO: DroidSansArabic lacks the glyph of U+FD3E ORNATE LEFT PARENTHESIS + // TODO: DroidSansArabic lacks the glyph of U+FD3F ORNATE RIGHT PARENTHESIS + /* 53 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", + /* 54 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // The following characters don't need BIDI mirroring. + // U+2018: "‘" LEFT SINGLE QUOTATION MARK + // U+2019: "’" RIGHT SINGLE QUOTATION MARK + // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK + // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK + // U+201C: "“" LEFT DOUBLE QUOTATION MARK + // U+201D: "”" RIGHT DOUBLE QUOTATION MARK + // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK + // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK + /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", + /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", + /* 57 */ null, + /* 58 */ null, // U+0661: "١" ARABIC-INDIC DIGIT ONE - /* 53 */ "\u0661", + /* 59 */ "\u0661", // U+0662: "٢" ARABIC-INDIC DIGIT TWO - /* 54 */ "\u0662", + /* 60 */ "\u0662", // U+0663: "٣" ARABIC-INDIC DIGIT THREE - /* 55 */ "\u0663", + /* 61 */ "\u0663", // U+0664: "٤" ARABIC-INDIC DIGIT FOUR - /* 56 */ "\u0664", + /* 62 */ "\u0664", // U+0665: "٥" ARABIC-INDIC DIGIT FIVE - /* 57 */ "\u0665", + /* 63 */ "\u0665", // U+0666: "٦" ARABIC-INDIC DIGIT SIX - /* 58 */ "\u0666", + /* 64 */ "\u0666", // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN - /* 59 */ "\u0667", + /* 65 */ "\u0667", // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT - /* 60 */ "\u0668", + /* 66 */ "\u0668", // U+0669: "٩" ARABIC-INDIC DIGIT NINE - /* 61 */ "\u0669", + /* 67 */ "\u0669", // U+0660: "٠" ARABIC-INDIC DIGIT ZERO - /* 62 */ "\u0660", - /* 63 */ "1", - /* 64 */ "2", - /* 65 */ "3", - /* 66 */ "4", - /* 67 */ "5", - /* 68 */ "6", - /* 69 */ "7", - /* 70 */ "8", - /* 71 */ "9", + /* 68 */ "\u0660", + /* 69 */ "1", + /* 70 */ "2", + /* 71 */ "3", + /* 72 */ "4", + /* 73 */ "5", + /* 74 */ "6", + /* 75 */ "7", + /* 76 */ "8", + /* 77 */ "9", // U+066B: "٫" ARABIC DECIMAL SEPARATOR // U+066C: "٬" ARABIC THOUSANDS SEPARATOR - /* 72 */ "0,\u066B,\u066C", - /* 73~ */ - null, null, null, null, null, null, null, null, null, null, null, null, - /* ~84 */ + /* 78 */ "0,\u066B,\u066C", + /* 79~ */ + null, null, null, null, null, null, null, null, null, null, + /* ~88 */ // U+060C: "،" ARABIC COMMA - /* 85 */ "\u060C", - /* 86 */ "\\,", - /* 87 */ null, - /* 88 */ null, - /* 89 */ "\u061F", - /* 90 */ "\u061B", + /* 89 */ "\u060C", + /* 90 */ "\\,", + /* 91 */ "\u061F", + /* 92 */ "\u061B", // U+066A: "٪" ARABIC PERCENT SIGN - /* 91 */ "\u066A", - /* 92 */ "?", - /* 93 */ ";", + /* 93 */ "\u066A", + /* 94 */ "?", + /* 95 */ ";", // U+2030: "‰" PER MILLE SIGN - /* 94 */ "%,\u2030", - /* 95~ */ + /* 96 */ "%,\u2030", + /* 97~ */ null, null, null, null, null, - /* ~99 */ + /* ~101 */ // U+060C: "،" ARABIC COMMA // U+061B: "؛" ARABIC SEMICOLON // U+061F: "؟" ARABIC QUESTION MARK - /* 100 */ "\u060C", - /* 101 */ ".", - /* 102 */ "\u061F", - /* 103 */ "\u064B", - /* 104 */ "\u061F,\u061B,!,:,-,/,\',\"", + /* 102 */ "\u060C", + /* 103 */ ".", + /* 104 */ "\u061F", + /* 105 */ "\u064B", + /* 106 */ "\u061F,\u061B,!,:,-,/,\',\"", // U+0651: "ّ" ARABIC SHADDA // U+0652: "ْ" ARABIC SUKUN // U+064C: "ٌ" ARABIC DAMMATAN // U+0653: "ٓ" ARABIC MADDAH ABOVE - // U+064F: "ُ" ARABIC DAMMA U+0650: "ِ" ARABIC KASRA + // U+064F: "ُ" ARABIC DAMMA + // U+0650: "ِ" ARABIC KASRA // U+064E: "َ" ARABIC FATHA // U+064B: "ً" ARABIC FATHATAN // U+0640: "ـ" ARABIC TATWEEL - // U+064D: "ٍ" ARABIC KASRATAN U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF + // U+064D: "ٍ" ARABIC KASRATAN + // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF // U+0654: "ٔ" ARABIC HAMZA ABOVE - // U+0655: "ٕ" ARABIC HAMZA BELOW In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. - /* 105 */ "\u0651,\u0652,\u064C,\u0653,\u064F,\u0650,\u064E,\u064B,\u0640\u0640\u0640|\u0640,\u064D,\u0654,\u0656,\u0655,\u0670", + // U+0655: "ٕ" ARABIC HAMZA BELOW + // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. + /* 107 */ "\u0651,\u0652,\u064C,\u0653,\u064F,\u0650,\u064E,\u064B,\u0640\u0640\u0640|\u0640,\u064D,\u0654,\u0656,\u0655,\u0670", // U+266A: "♪" EIGHTH NOTE - /* 106 */ "\u266A", - // U+2605: "★" BLACK STAR - // U+066D: "٭" ARABIC FIVE POINTED STAR - /* 107 */ "\u2605,\u066D", - /* 108 */ null, - // The all letters need to be mirrored are found at - // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt U+FD3E: "﴾" ORNATE LEFT PARENTHESIS - // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS TODO: DroidSansArabic lacks the glyph of U+FD3E ORNATE LEFT PARENTHESIS TODO: DroidSansArabic lacks the glyph of U+FD3F ORNATE RIGHT PARENTHESIS - /* 109 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", - /* 110 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", - // U+2264: "≤" LESS-THAN OR EQUAL TO - // U+2265: "≥" GREATER-THAN EQUAL TO - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - // The following characters don't need BIDI mirroring. - // U+2018: "‘" LEFT SINGLE QUOTATION MARK - // U+2019: "’" RIGHT SINGLE QUOTATION MARK - // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK - // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK - // U+201C: "“" LEFT DOUBLE QUOTATION MARK - // U+201D: "”" RIGHT DOUBLE QUOTATION MARK - // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK - // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - /* 111 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", - /* 112 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", + /* 108 */ "\u266A", }; /* Language be: Belarusian */ @@ -755,7 +769,7 @@ public final class KeyboardLabelsSet { // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0103", + /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE @@ -770,7 +784,7 @@ public final class KeyboardLabelsSet { // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - /* 3 */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8\u014D,\u00F5", + /* 3 */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE @@ -954,134 +968,143 @@ public final class KeyboardLabelsSet { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, /* ~41 */ - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK + // <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB", - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK + // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", /* 44~ */ null, null, null, null, null, /* ~48 */ // U+061F: "؟" ARABIC QUESTION MARK // U+060C: "،" ARABIC COMMA - // U+061B: "؛" ARABIC SEMICOLON U+0650: "ِ" ARABIC KASRA + // U+061B: "؛" ARABIC SEMICOLON + // U+0650: "ِ" ARABIC KASRA // U+064E: "َ" ARABIC FATHA // U+064D: "ٍ" ARABIC KASRATAN // U+064B: "ً" ARABIC FATHATAN // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF // U+0655: "ٕ" ARABIC HAMZA BELOW - // U+0654: "ٔ" ARABIC HAMZA ABOVE U+064F: "ُ" ARABIC DAMMA + // U+0654: "ٔ" ARABIC HAMZA ABOVE + // U+064F: "ُ" ARABIC DAMMA // U+064C: "ٌ" ARABIC DAMMATAN // U+0651: "ّ" ARABIC SHADDA // U+0652: "ْ" ARABIC SUKUN // U+0653: "ٓ" ARABIC MADDAH ABOVE - // U+0640: "ـ" ARABIC TATWEEL In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. + // U+0640: "ـ" ARABIC TATWEEL + // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. /* 49 */ "!fixedColumnOrder!8,\",\',-,:,!,\u061F,\u060C,\u061B,\u0650,\u064E,\u064D,\u064B,\u0656,\u0670,\u0655,\u0654,\u064F,\u064C,\u0651,\u0652,\u0653,\u0640\u0640\u0640|\u0640,/", /* 50 */ "\u064B", - /* 51 */ null, + // U+2605: "★" BLACK STAR + // U+066D: "٭" ARABIC FIVE POINTED STAR + /* 51 */ "\u2605,\u066D", /* 52 */ null, + // The all letters need to be mirrored are found at + // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt + // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS + // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS + // TODO: DroidSansArabic lacks the glyph of U+FD3E ORNATE LEFT PARENTHESIS + // TODO: DroidSansArabic lacks the glyph of U+FD3F ORNATE RIGHT PARENTHESIS + /* 53 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", + /* 54 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // The following characters don't need BIDI mirroring. + // U+2018: "‘" LEFT SINGLE QUOTATION MARK + // U+2019: "’" RIGHT SINGLE QUOTATION MARK + // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK + // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK + // U+201C: "“" LEFT DOUBLE QUOTATION MARK + // U+201D: "”" RIGHT DOUBLE QUOTATION MARK + // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK + // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK + /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", + /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", + /* 57 */ null, + /* 58 */ null, // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE - /* 53 */ "\u06F1", + /* 59 */ "\u06F1", // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO - /* 54 */ "\u06F2", + /* 60 */ "\u06F2", // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE - /* 55 */ "\u06F3", + /* 61 */ "\u06F3", // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR - /* 56 */ "\u06F4", + /* 62 */ "\u06F4", // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE - /* 57 */ "\u06F5", + /* 63 */ "\u06F5", // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX - /* 58 */ "\u06F6", + /* 64 */ "\u06F6", // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN - /* 59 */ "\u06F7", + /* 65 */ "\u06F7", // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT - /* 60 */ "\u06F8", + /* 66 */ "\u06F8", // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE - /* 61 */ "\u06F9", + /* 67 */ "\u06F9", // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO - /* 62 */ "\u06F0", - /* 63 */ "1", - /* 64 */ "2", - /* 65 */ "3", - /* 66 */ "4", - /* 67 */ "5", - /* 68 */ "6", - /* 69 */ "7", - /* 70 */ "8", - /* 71 */ "9", + /* 68 */ "\u06F0", + /* 69 */ "1", + /* 70 */ "2", + /* 71 */ "3", + /* 72 */ "4", + /* 73 */ "5", + /* 74 */ "6", + /* 75 */ "7", + /* 76 */ "8", + /* 77 */ "9", // U+066B: "٫" ARABIC DECIMAL SEPARATOR // U+066C: "٬" ARABIC THOUSANDS SEPARATOR - /* 72 */ "0,\u066B,\u066C", - /* 73~ */ - null, null, null, null, null, null, null, null, null, null, null, null, - /* ~84 */ + /* 78 */ "0,\u066B,\u066C", + /* 79~ */ + null, null, null, null, null, null, null, null, null, null, + /* ~88 */ // U+060C: "،" ARABIC COMMA - /* 85 */ "\u060C", - /* 86 */ "\\,", - /* 87 */ null, - /* 88 */ null, - /* 89 */ "\u061F", - /* 90 */ "\u061B", + /* 89 */ "\u060C", + /* 90 */ "\\,", + /* 91 */ "\u061F", + /* 92 */ "\u061B", // U+066A: "٪" ARABIC PERCENT SIGN - /* 91 */ "\u066A", - /* 92 */ "?", - /* 93 */ ";", + /* 93 */ "\u066A", + /* 94 */ "?", + /* 95 */ ";", // U+2030: "‰" PER MILLE SIGN - /* 94 */ "%,\u2030", + /* 96 */ "%,\u2030", // U+060C: "،" ARABIC COMMA // U+061B: "؛" ARABIC SEMICOLON // U+061F: "؟" ARABIC QUESTION MARK - /* 95 */ "\u060C", - /* 96 */ "!", - /* 97 */ "!,\\,", - /* 98 */ "\u061F", - /* 99 */ "\u061F,?", - /* 100~ */ + /* 97 */ "\u060C", + /* 98 */ "!", + /* 99 */ "!,\\,", + /* 100 */ "\u061F", + /* 101 */ "\u061F,?", + /* 102~ */ null, null, null, - /* ~102 */ - /* 103 */ "\u064B", - /* 104 */ "\u061F,\u061B,!,:,-,/,\',\"", + /* ~104 */ + /* 105 */ "\u064B", + /* 106 */ "\u061F,\u061B,!,:,-,/,\',\"", // U+0651: "ّ" ARABIC SHADDA // U+0652: "ْ" ARABIC SUKUN // U+064C: "ٌ" ARABIC DAMMATAN // U+0653: "ٓ" ARABIC MADDAH ABOVE - // U+064F: "ُ" ARABIC DAMMA U+0650: "ِ" ARABIC KASRA + // U+064F: "ُ" ARABIC DAMMA + // U+0650: "ِ" ARABIC KASRA // U+064E: "َ" ARABIC FATHA // U+064B: "ً" ARABIC FATHATAN // U+0640: "ـ" ARABIC TATWEEL - // U+064D: "ٍ" ARABIC KASRATAN U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF + // U+064D: "ٍ" ARABIC KASRATAN + // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF // U+0654: "ٔ" ARABIC HAMZA ABOVE - // U+0655: "ٕ" ARABIC HAMZA BELOW In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. - /* 105 */ "\u0651,\u0652,\u064C,\u0653,\u064F,\u0650,\u064E,\u064B,\u0640\u0640\u0640|\u0640,\u064D,\u0654,\u0656,\u0655,_,\u0670", + // U+0655: "ٕ" ARABIC HAMZA BELOW + // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. + /* 107 */ "\u0651,\u0652,\u064C,\u0653,\u064F,\u0650,\u064E,\u064B,\u0640\u0640\u0640|\u0640,\u064D,\u0654,\u0656,\u0655,_,\u0670", // U+266A: "♪" EIGHTH NOTE - /* 106 */ "\u266A", - // U+2605: "★" BLACK STAR - // U+066D: "٭" ARABIC FIVE POINTED STAR - /* 107 */ "\u2605,\u066D", - /* 108 */ null, - // The all letters need to be mirrored are found at - // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt U+FD3E: "﴾" ORNATE LEFT PARENTHESIS - // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS TODO: DroidSansArabic lacks the glyph of U+FD3E ORNATE LEFT PARENTHESIS TODO: DroidSansArabic lacks the glyph of U+FD3F ORNATE RIGHT PARENTHESIS - /* 109 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", - /* 110 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", - // U+2264: "≤" LESS-THAN OR EQUAL TO - // U+2265: "≥" GREATER-THAN EQUAL TO - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - // The following characters don't need BIDI mirroring. - // U+2018: "‘" LEFT SINGLE QUOTATION MARK - // U+2019: "’" RIGHT SINGLE QUOTATION MARK - // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK - // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK - // U+201C: "“" LEFT DOUBLE QUOTATION MARK - // U+201D: "”" RIGHT DOUBLE QUOTATION MARK - // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK - // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - /* 111 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", - /* 112 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", + /* 108 */ "\u266A", }; /* Language fi: Finnish */ @@ -1190,38 +1213,38 @@ public final class KeyboardLabelsSet { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, - /* ~52 */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~58 */ // U+0967: "१" DEVANAGARI DIGIT ONE - /* 53 */ "\u0967", + /* 59 */ "\u0967", // U+0968: "२" DEVANAGARI DIGIT TWO - /* 54 */ "\u0968", + /* 60 */ "\u0968", // U+0969: "३" DEVANAGARI DIGIT THREE - /* 55 */ "\u0969", + /* 61 */ "\u0969", // U+096A: "४" DEVANAGARI DIGIT FOUR - /* 56 */ "\u096A", + /* 62 */ "\u096A", // U+096B: "५" DEVANAGARI DIGIT FIVE - /* 57 */ "\u096B", + /* 63 */ "\u096B", // U+096C: "६" DEVANAGARI DIGIT SIX - /* 58 */ "\u096C", + /* 64 */ "\u096C", // U+096D: "७" DEVANAGARI DIGIT SEVEN - /* 59 */ "\u096D", + /* 65 */ "\u096D", // U+096E: "८" DEVANAGARI DIGIT EIGHT - /* 60 */ "\u096E", + /* 66 */ "\u096E", // U+096F: "९" DEVANAGARI DIGIT NINE - /* 61 */ "\u096F", + /* 67 */ "\u096F", // U+0966: "०" DEVANAGARI DIGIT ZERO - /* 62 */ "\u0966", - /* 63 */ "1", - /* 64 */ "2", - /* 65 */ "3", - /* 66 */ "4", - /* 67 */ "5", - /* 68 */ "6", - /* 69 */ "7", - /* 70 */ "8", - /* 71 */ "9", - /* 72 */ "0", + /* 68 */ "\u0966", + /* 69 */ "1", + /* 70 */ "2", + /* 71 */ "3", + /* 72 */ "4", + /* 73 */ "5", + /* 74 */ "6", + /* 75 */ "7", + /* 76 */ "8", + /* 77 */ "9", + /* 78 */ "0", }; /* Language hr: Croatian */ @@ -1411,26 +1434,24 @@ public final class KeyboardLabelsSet { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, /* ~41 */ - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK + // <string name="more_keys_for_double_quote">“,”,„,‟,«|»,»|«</string> /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB", - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK + // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«|»,»|«;,‘,’,‚,‛</string> /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B", /* 44~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, - /* ~106 */ + null, null, null, null, null, null, null, + /* ~50 */ // U+2605: "★" BLACK STAR - /* 107 */ "\u2605", + /* 51 */ "\u2605", // U+00B1: "±" PLUS-MINUS SIGN // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN - /* 108 */ "\u00B1,\uFB29", + /* 52 */ "\u00B1,\uFB29", // The all letters need to be mirrored are found at // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt - /* 109 */ "!fixedColumnOrder!3,<|>,{|},[|]", - /* 110 */ "!fixedColumnOrder!3,>|<,}|{,]|[", + /* 53 */ "!fixedColumnOrder!3,<|>,{|},[|]", + /* 54 */ "!fixedColumnOrder!3,>|<,}|{,]|[", // U+2264: "≤" LESS-THAN OR EQUAL TO // U+2265: "≥" GREATER-THAN EQUAL TO // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK @@ -1446,8 +1467,8 @@ public final class KeyboardLabelsSet { // U+201D: "”" RIGHT DOUBLE QUOTATION MARK // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK - /* 111 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", - /* 112 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", + /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", + /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", }; /* Language ky: Kirghiz */ @@ -1682,9 +1703,12 @@ public final class KeyboardLabelsSet { // U+201C: "“" LEFT DOUBLE QUOTATION MARK // U+201D: "”" RIGHT DOUBLE QUOTATION MARK // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK - // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. <string name="more_keys_for_double_quote">!fixedColumnOrder!6,„,“,”,‟,«,»</string> + // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. + // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,„,“,”,‟,«,»</string> /* 42 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB", - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. + // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", }; @@ -2100,9 +2124,12 @@ public final class KeyboardLabelsSet { // U+201C: "“" LEFT DOUBLE QUOTATION MARK // U+201D: "”" RIGHT DOUBLE QUOTATION MARK // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK - // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. <string name="more_keys_for_double_quote">!fixedColumnOrder!6,„,“,”,‟,«,»</string> + // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. + // <string name="more_keys_for_double_quote">!fixedColumnOrder!6,„,“,”,‟,«,»</string> /* 42 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB", - // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> + // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. + // <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,“,”,„,‟,«,»,‘,’,‚,‛</string> /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B", }; diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java index b24f06472..28cec56e6 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java @@ -16,6 +16,10 @@ package com.android.inputmethod.latin; +import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE; +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE; +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; + import android.view.inputmethod.InputMethodSubtype; import java.util.HashMap; @@ -24,9 +28,11 @@ public class AdditionalSubtype { public static final String QWERTY = "qwerty"; public static final String QWERTZ = "qwertz"; public static final String AZERTY = "azerty"; - - private static final String SUBTYPE_MODE_KEYBOARD = "keyboard"; - private static final String SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE = "isAdditionalSubtype"; + public static final String[] PREDEFINED_KEYBOARD_LAYOUT_SET = { + QWERTY, + QWERTZ, + AZERTY + }; // Keyboard layout to subtype name resource id map. private static final HashMap<String, Integer> sKeyboardLayoutToNameIdsMap = @@ -38,33 +44,57 @@ public class AdditionalSubtype { sKeyboardLayoutToNameIdsMap.put(AZERTY, R.string.subtype_generic_azerty); } + private AdditionalSubtype() { + // This utility class is not publicly instantiable. + } + public static boolean isAdditionalSubtype(InputMethodSubtype subtype) { - return subtype.containsExtraValueKey(SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE); + return subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE); } + private static final String LOCALE_AND_LAYOUT_SEPARATOR = ":"; + public static final String PREF_SUBTYPE_SEPARATOR = ";"; + public static InputMethodSubtype createAdditionalSubtype( - String localeString, String keyboardLayoutSet) { - final String extraValue = String.format( - "%s=%s,%s", LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET, keyboardLayoutSet, - SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE); - Integer nameId = sKeyboardLayoutToNameIdsMap.get(keyboardLayoutSet); + String localeString, String keyboardLayoutSetName, String extraValue) { + final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName; + final String filteredExtraValue = StringUtils.appendToCsvIfNotExists( + IS_ADDITIONAL_SUBTYPE, extraValue); + Integer nameId = sKeyboardLayoutToNameIdsMap.get(keyboardLayoutSetName); if (nameId == null) nameId = R.string.subtype_generic; return new InputMethodSubtype(nameId, R.drawable.ic_subtype_keyboard, - localeString, SUBTYPE_MODE_KEYBOARD, extraValue, false, false); + localeString, KEYBOARD_MODE, + layoutExtraValue + "," + filteredExtraValue, false, false); } - private static final String LOCALE_AND_LAYOUT_SEPARATOR = ":"; - private static final String SUBTYPE_SEPARATOR = ","; + public static String getPrefSubtype(InputMethodSubtype subtype) { + final String localeString = subtype.getLocale(); + final String keyboardLayoutSetName = SubtypeLocale.getKeyboardLayoutSetName(subtype); + final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName; + final String extraValue = StringUtils.removeFromCsvIfExists(layoutExtraValue, + StringUtils.removeFromCsvIfExists(IS_ADDITIONAL_SUBTYPE, subtype.getExtraValue())); + final String basePrefSubtype = localeString + LOCALE_AND_LAYOUT_SEPARATOR + + keyboardLayoutSetName; + return extraValue.isEmpty() ? basePrefSubtype + : basePrefSubtype + LOCALE_AND_LAYOUT_SEPARATOR + extraValue; + } + + public static InputMethodSubtype createAdditionalSubtype(String prefSubtype) { + final String elems[] = prefSubtype.split(LOCALE_AND_LAYOUT_SEPARATOR); + if (elems.length < 2 || elems.length > 3) { + throw new RuntimeException("Unknown additional subtype specified: " + prefSubtype); + } + final String localeString = elems[0]; + final String keyboardLayoutSetName = elems[1]; + final String extraValue = (elems.length == 3) ? elems[2] : null; + return createAdditionalSubtype(localeString, keyboardLayoutSetName, extraValue); + } - public static InputMethodSubtype[] createAdditionalSubtypesArray(String csvSubtypes) { - final String[] subtypeSpecs = csvSubtypes.split(SUBTYPE_SEPARATOR); - final InputMethodSubtype[] subtypesArray = new InputMethodSubtype[subtypeSpecs.length]; - for (int i = 0; i < subtypeSpecs.length; i++) { - final String elems[] = subtypeSpecs[i].split(LOCALE_AND_LAYOUT_SEPARATOR); - final String localeString = elems[0]; - final String keyboardLayoutSetName = elems[1]; - subtypesArray[i] = AdditionalSubtype.createAdditionalSubtype( - localeString, keyboardLayoutSetName); + public static InputMethodSubtype[] createAdditionalSubtypesArray(String prefSubtypes) { + final String[] prefSubtypeArray = prefSubtypes.split(PREF_SUBTYPE_SEPARATOR); + final InputMethodSubtype[] subtypesArray = new InputMethodSubtype[prefSubtypeArray.length]; + for (int i = 0; i < prefSubtypeArray.length; i++) { + subtypesArray[i] = createAdditionalSubtype(prefSubtypeArray[i]); } return subtypesArray; } diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java new file mode 100644 index 000000000..7a22c9742 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java @@ -0,0 +1,440 @@ +/** + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package com.android.inputmethod.latin; + +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.ASCII_CAPABLE; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.preference.DialogPreference; +import android.preference.Preference; +import android.preference.PreferenceFragment; +import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; +import android.widget.ArrayAdapter; +import android.widget.Spinner; +import android.widget.SpinnerAdapter; + +import java.util.Locale; +import java.util.TreeSet; + +public class AdditionalSubtypeSettings extends PreferenceFragment { + private SharedPreferences mPrefs; + private SubtypeLocaleAdapter mSubtypeLocaleAdapter; + private KeyboardLayoutSetAdapter mKeyboardLayoutSetAdapter; + + private PreferenceGroup mSubtypePrefGroup; + + private static final int MENU_ADD_SUBTYPE = Menu.FIRST; + + static class SubtypeLocaleItem extends Pair<String, String> + implements Comparable<SubtypeLocaleItem> { + public SubtypeLocaleItem(String localeString, String displayName) { + super(localeString, displayName); + } + + public SubtypeLocaleItem(String localeString) { + this(localeString, getDisplayName(localeString)); + } + + @Override + public String toString() { + return second; + } + + @Override + public int compareTo(SubtypeLocaleItem o) { + return first.compareTo(o.first); + } + + private static String getDisplayName(String localeString) { + final Locale locale = LocaleUtils.constructLocaleFromString(localeString); + return StringUtils.toTitleCase(locale.getDisplayName(locale), locale); + } + } + + static class SubtypeLocaleAdapter extends ArrayAdapter<SubtypeLocaleItem> { + public SubtypeLocaleAdapter(Context context) { + super(context, android.R.layout.simple_spinner_item); + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + final TreeSet<SubtypeLocaleItem> items = new TreeSet<SubtypeLocaleItem>(); + final InputMethodInfo imi = ImfUtils.getInputMethodInfoOfThisIme(context); + final int count = imi.getSubtypeCount(); + for (int i = 0; i < count; i++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(i); + if (subtype.containsExtraValueKey(ASCII_CAPABLE)) { + items.add(createItem(context, subtype.getLocale())); + } + } + // TODO: Should filter out already existing combinations of locale and layout. + addAll(items); + } + + public static SubtypeLocaleItem createItem(Context context, String localeString) { + if (localeString.equals(SubtypeLocale.NO_LANGUAGE)) { + final String displayName = context.getString(R.string.subtype_no_language); + return new SubtypeLocaleItem(localeString, displayName); + } else { + return new SubtypeLocaleItem(localeString); + } + } + } + + static class KeyboardLayoutSetItem extends Pair<String, String> { + public KeyboardLayoutSetItem(String keyboardLayoutSetName) { + super(keyboardLayoutSetName, getDisplayName(keyboardLayoutSetName)); + } + + @Override + public String toString() { + return second; + } + + private static String getDisplayName(String keyboardLayoutSetName) { + return keyboardLayoutSetName.toUpperCase(); + } + } + + static class KeyboardLayoutSetAdapter extends ArrayAdapter<KeyboardLayoutSetItem> { + public KeyboardLayoutSetAdapter(Context context) { + super(context, android.R.layout.simple_spinner_item); + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + // TODO: Should filter out already existing combinations of locale and layout. + for (final String layout : AdditionalSubtype.PREDEFINED_KEYBOARD_LAYOUT_SET) { + add(new KeyboardLayoutSetItem(layout)); + } + } + } + + private interface SubtypeDialogProxy { + public void onRemovePressed(SubtypePreference subtypePref); + public SubtypeLocaleAdapter getSubtypeLocaleAdapter(); + public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter(); + } + + static class SubtypePreference extends DialogPreference { + private InputMethodSubtype mSubtype; + + private final SubtypeDialogProxy mProxy; + private Spinner mSubtypeLocaleSpinner; + private Spinner mKeyboardLayoutSetSpinner; + + public SubtypePreference(Context context, InputMethodSubtype subtype, + SubtypeDialogProxy proxy) { + super(context, null); + setPersistent(false); + mProxy = proxy; + setSubtype(subtype); + } + + public void show() { + showDialog(null); + } + + public InputMethodSubtype getSubtype() { + return mSubtype; + } + + public void setSubtype(InputMethodSubtype subtype) { + mSubtype = subtype; + if (subtype == null) { + setTitle(null); + setDialogTitle(R.string.add_style); + } else { + final String displayName = SubtypeLocale.getFullDisplayName(subtype); + setTitle(displayName); + setDialogTitle(displayName); + } + } + + @Override + protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { + final Context context = builder.getContext(); + final View v = LayoutInflater.from(context).inflate( + R.layout.additional_subtype_dialog, null); + builder.setView(v); + mSubtypeLocaleSpinner = (Spinner) v.findViewById(R.id.subtype_locale_spinner); + mSubtypeLocaleSpinner.setAdapter(mProxy.getSubtypeLocaleAdapter()); + mKeyboardLayoutSetSpinner = (Spinner) v.findViewById(R.id.keyboard_layout_set_spinner); + mKeyboardLayoutSetSpinner.setAdapter(mProxy.getKeyboardLayoutSetAdapter()); + + if (mSubtype == null) { + builder.setPositiveButton(R.string.add, this) + .setNegativeButton(android.R.string.cancel, this); + } else { + builder.setPositiveButton(R.string.save, this) + .setNeutralButton(android.R.string.cancel, this) + .setNegativeButton(R.string.remove, this); + final SubtypeLocaleItem localeItem = SubtypeLocaleAdapter.createItem( + context, mSubtype.getLocale()); + final KeyboardLayoutSetItem layoutItem = new KeyboardLayoutSetItem( + SubtypeLocale.getKeyboardLayoutSetName(mSubtype)); + setSpinnerPosition(mSubtypeLocaleSpinner, localeItem); + setSpinnerPosition(mKeyboardLayoutSetSpinner, layoutItem); + } + } + + private static void setSpinnerPosition(Spinner spinner, Object itemToSelect) { + final SpinnerAdapter adapter = spinner.getAdapter(); + final int count = adapter.getCount(); + for (int i = 0; i < count; i++) { + final Object item = spinner.getItemAtPosition(i); + if (item.equals(itemToSelect)) { + spinner.setSelection(i); + return; + } + } + } + + @Override + public void onClick(DialogInterface dialog, int which) { + super.onClick(dialog, which); + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + final SubtypeLocaleItem locale = + (SubtypeLocaleItem) mSubtypeLocaleSpinner.getSelectedItem(); + final KeyboardLayoutSetItem layout = + (KeyboardLayoutSetItem) mKeyboardLayoutSetSpinner.getSelectedItem(); + final InputMethodSubtype subtype = AdditionalSubtype.createAdditionalSubtype( + locale.first, layout.first, ASCII_CAPABLE); + setSubtype(subtype); + notifyChanged(); + break; + case DialogInterface.BUTTON_NEUTRAL: + // Nothing to do + break; + case DialogInterface.BUTTON_NEGATIVE: + mProxy.onRemovePressed(this); + break; + } + } + + @Override + protected Parcelable onSaveInstanceState() { + final SavedState myState = new SavedState(super.onSaveInstanceState()); + myState.mSubtype = mSubtype; + return myState; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof SavedState) { + final SavedState myState = (SavedState) state; + super.onRestoreInstanceState(state); + setSubtype(myState.mSubtype); + } else { + super.onRestoreInstanceState(state); + } + } + + static class SavedState extends Preference.BaseSavedState { + InputMethodSubtype mSubtype; + private static final byte VALID = 1; + private static final byte INVALID = 0; + + public SavedState(Parcelable superState) { + super(superState); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + if (mSubtype != null) { + dest.writeByte(VALID); + mSubtype.writeToParcel(dest, 0); + } else { + dest.writeByte(INVALID); + } + } + + public SavedState(Parcel source) { + super(source); + if (source.readByte() == VALID) { + mSubtype = source.readParcelable(null); + } else { + mSubtype = null; + } + } + + public static final Parcelable.Creator<SavedState> CREATOR = + new Parcelable.Creator<SavedState>() { + @Override + public SavedState createFromParcel(Parcel source) { + return new SavedState(source); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + } + + public AdditionalSubtypeSettings() { + // Empty constructor for fragment generation. + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.additional_subtype_settings); + setHasOptionsMenu(true); + mSubtypePrefGroup = getPreferenceScreen(); + + mPrefs = getPreferenceManager().getSharedPreferences(); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + final Context context = getActivity(); + mSubtypeLocaleAdapter = new SubtypeLocaleAdapter(context); + mKeyboardLayoutSetAdapter = new KeyboardLayoutSetAdapter(context); + + // TODO: Restore editing dialog if any. + } + + private final SubtypeDialogProxy mSubtypeProxy = new SubtypeDialogProxy() { + @Override + public void onRemovePressed(SubtypePreference subtypePref) { + final PreferenceGroup group = mSubtypePrefGroup; + if (group != null) { + group.removePreference(subtypePref); + } + } + + @Override + public SubtypeLocaleAdapter getSubtypeLocaleAdapter() { + return mSubtypeLocaleAdapter; + } + + @Override + public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter() { + return mKeyboardLayoutSetAdapter; + } + }; + + private void setPrefSubtypes(String prefSubtypes, Context context) { + final PreferenceGroup group = mSubtypePrefGroup; + group.removeAll(); + final String[] prefSubtypeArray = prefSubtypes.split( + AdditionalSubtype.PREF_SUBTYPE_SEPARATOR); + for (final String prefSubtype : prefSubtypeArray) { + final InputMethodSubtype subtype = + AdditionalSubtype.createAdditionalSubtype(prefSubtype); + final SubtypePreference pref = new SubtypePreference( + context, subtype, mSubtypeProxy); + group.addPreference(pref); + } + } + + private String getPrefSubtypes() { + final StringBuilder sb = new StringBuilder(); + final int count = mSubtypePrefGroup.getPreferenceCount(); + for (int i = 0; i < count; i++) { + final Preference pref = mSubtypePrefGroup.getPreference(i); + if (pref instanceof SubtypePreference) { + final InputMethodSubtype subtype = ((SubtypePreference)pref).getSubtype(); + if (sb.length() > 0) { + sb.append(AdditionalSubtype.PREF_SUBTYPE_SEPARATOR); + } + sb.append(AdditionalSubtype.getPrefSubtype(subtype)); + } + } + return sb.toString(); + } + + @Override + public void onResume() { + super.onResume(); + + final String prefSubtypes = + SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources()); + setPrefSubtypes(prefSubtypes, getActivity()); + } + + @Override + public void onPause() { + super.onPause(); + final String oldSubtypes = SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources()); + final String prefSubtypes = getPrefSubtypes(); + if (prefSubtypes.equals(oldSubtypes)) { + return; + } + + final SharedPreferences.Editor editor = mPrefs.edit(); + try { + editor.putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes); + } finally { + editor.apply(); + } + final InputMethodSubtype[] subtypes = + AdditionalSubtype.createAdditionalSubtypesArray(prefSubtypes); + ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), subtypes); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // TODO: save editing dialog state. + } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen prefScreen, Preference pref) { + if (pref instanceof SubtypePreference) { + return true; + } + return super.onPreferenceTreeClick(prefScreen, pref); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + final MenuItem addSubtypeMenu = menu.add(0, MENU_ADD_SUBTYPE, 0, R.string.add_style); + addSubtypeMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + final int itemId = item.getItemId(); + if (itemId == MENU_ADD_SUBTYPE) { + final SubtypePreference subtypePref = new SubtypePreference( + getActivity(), null, mSubtypeProxy); + mSubtypePrefGroup.addPreference(subtypePref); + subtypePref.show(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java new file mode 100644 index 000000000..b205cc004 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.view.inputmethod.EditorInfo; + +public final class Constants { + public static final class ImeOption { + /** + * The private IME option used to indicate that no microphone should be shown for a given + * text field. For instance, this is specified by the search dialog when the dialog is + * already showing a voice search button. + * + * @deprecated Use {@link ImeOption#NO_MICROPHONE} with package name prefixed. + */ + @SuppressWarnings("dep-ann") + public static final String NO_MICROPHONE_COMPAT = "nm"; + + /** + * The private IME option used to indicate that no microphone should be shown for a given + * text field. For instance, this is specified by the search dialog when the dialog is + * already showing a voice search button. + */ + public static final String NO_MICROPHONE = "noMicrophoneKey"; + + /** + * The private IME option used to indicate that no settings key should be shown for a given + * text field. + */ + public static final String NO_SETTINGS_KEY = "noSettingsKey"; + + /** + * The private IME option used to indicate that the given text field needs ASCII code points + * input. + * + * @deprecated Use {@link EditorInfo#IME_FLAG_FORCE_ASCII}. + */ + @SuppressWarnings("dep-ann") + public static final String FORCE_ASCII = "forceAscii"; + + private ImeOption() { + // This utility class is not publicly instantiable. + } + } + + public static final class Subtype { + /** + * The subtype mode used to indicate that the subtype is a keyboard. + */ + public static final String KEYBOARD_MODE = "keyboard"; + + public static final class ExtraValue { + /** + * The subtype extra value used to indicate that the subtype keyboard layout set name. + */ + public static final String KEYBOARD_LAYOUT_SET = "KeyboardLayoutSet"; + + /** + * The subtype extra value used to indicate that the subtype keyboard layout is capable + * for typing ASCII characters. + */ + public static final String ASCII_CAPABLE = "AsciiCapable"; + + /** + * The subtype extra value used to indicate that the subtype require network connection + * to work. + */ + public static final String REQ_NETWORK_CONNECTIVITY = "requireNetworkConnectivity"; + + /** + * The subtype extra value used to indicate that the subtype is additional subtype + * that the user defined. This extra value is private to LatinIME. + */ + public static final String IS_ADDITIONAL_SUBTYPE = "isAdditionalSubtype"; + + private ExtraValue() { + // This utility class is not publicly instantiable. + } + } + + private Subtype() { + // This utility class is not publicly instantiable. + } + } + + private Constants() { + // This utility class is not publicly instantiable. + } +} diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 17d75368e..f5dc7b34a 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -30,7 +30,10 @@ import java.util.Locale; * Factory for dictionary instances. */ public class DictionaryFactory { - private static String TAG = DictionaryFactory.class.getSimpleName(); + private static final String TAG = DictionaryFactory.class.getSimpleName(); + // This class must be located in the same package as LatinIME.java. + private static final String RESOURCE_PACKAGE_NAME = + DictionaryFactory.class.getPackage().getName(); /** * Initializes a dictionary from a dictionary pack, with explicit flags. @@ -166,20 +169,19 @@ public class DictionaryFactory { */ private static int getMainDictionaryResourceIdIfAvailableForLocale(final Resources res, final Locale locale) { - final String packageName = LatinIME.class.getPackage().getName(); int resId; - // Try to find main_language_country dictionary. if (!locale.getCountry().isEmpty()) { final String dictLanguageCountry = MAIN_DICT_PREFIX + locale.toString().toLowerCase(); - if ((resId = res.getIdentifier(dictLanguageCountry, "raw", packageName)) != 0) { + if ((resId = res.getIdentifier( + dictLanguageCountry, "raw", RESOURCE_PACKAGE_NAME)) != 0) { return resId; } } // Try to find main_language dictionary. final String dictLanguage = MAIN_DICT_PREFIX + locale.getLanguage(); - if ((resId = res.getIdentifier(dictLanguage, "raw", packageName)) != 0) { + if ((resId = res.getIdentifier(dictLanguage, "raw", RESOURCE_PACKAGE_NAME)) != 0) { return resId; } @@ -195,7 +197,6 @@ public class DictionaryFactory { public static int getMainDictionaryResourceId(final Resources res, final Locale locale) { int resourceId = getMainDictionaryResourceIdIfAvailableForLocale(res, locale); if (0 != resourceId) return resourceId; - final String packageName = LatinIME.class.getPackage().getName(); - return res.getIdentifier(DEFAULT_MAIN_DICT, "raw", packageName); + return res.getIdentifier(DEFAULT_MAIN_DICT, "raw", RESOURCE_PACKAGE_NAME); } } diff --git a/java/src/com/android/inputmethod/latin/ImfUtils.java b/java/src/com/android/inputmethod/latin/ImfUtils.java index bd7d89fe7..4633b82f5 100644 --- a/java/src/com/android/inputmethod/latin/ImfUtils.java +++ b/java/src/com/android/inputmethod/latin/ImfUtils.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE; + import android.content.Context; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -131,7 +133,7 @@ public class ImfUtils { // both explicitly and implicitly enabled input method subtype. // (The current IME should be LatinIME.) for (InputMethodSubtype subtype : subtypes) { - if (SubtypeSwitcher.KEYBOARD_MODE.equals(subtype.getMode())) { + if (KEYBOARD_MODE.equals(subtype.getMode())) { ++keyboardCount; } } diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index a6ce04069..9c32f947c 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -162,4 +162,12 @@ public class InputAttributes { + "\n mIsSettingsSuggestionStripOn = " + mIsSettingsSuggestionStripOn + "\n mApplicationSpecifiedCompletionOn = " + mApplicationSpecifiedCompletionOn; } + + public static boolean inPrivateImeOptions(String packageName, String key, + EditorInfo editorInfo) { + if (editorInfo == null) return false; + final String findingKey = (packageName != null) ? packageName + "." + key + : key; + return StringUtils.containsInCsv(findingKey, editorInfo.privateImeOptions); + } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 682901cbc..41884d34a 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -16,6 +16,10 @@ package com.android.inputmethod.latin; +import static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII; +import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE; +import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT; + import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -81,49 +85,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private static final boolean TRACE = false; private static boolean DEBUG; - /** - * The private IME option used to indicate that no microphone should be - * shown for a given text field. For instance, this is specified by the - * search dialog when the dialog is already showing a voice search button. - * - * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed. - */ - @SuppressWarnings("dep-ann") - public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm"; - - /** - * The private IME option used to indicate that no microphone should be - * shown for a given text field. For instance, this is specified by the - * search dialog when the dialog is already showing a voice search button. - */ - public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey"; - - /** - * The private IME option used to indicate that no settings key should be - * shown for a given text field. - */ - public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey"; - - /** - * The private IME option used to indicate that the given text field needs - * ASCII code points input. - * - * @deprecated Use {@link EditorInfo#IME_FLAG_FORCE_ASCII}. - */ - @SuppressWarnings("dep-ann") - public static final String IME_OPTION_FORCE_ASCII = "forceAscii"; - - /** - * The subtype extra value used to indicate that the subtype keyboard layout set name. - */ - public static final String SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET = "KeyboardLayoutSet"; - - /** - * The subtype extra value used to indicate that the subtype keyboard layout is capable for - * typing ASCII characters. - */ - public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable"; - private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; // How many continuous deletes at which to start deleting at a higher speed. @@ -193,6 +154,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private final SubtypeSwitcher mSubtypeSwitcher; private boolean mShouldSwitchToLastSubtype = true; + private boolean mIsMainDictionaryAvailable; private UserDictionary mUserDictionary; private UserHistoryDictionary mUserHistoryDictionary; private boolean mIsUserDictionaryAvailable; @@ -488,14 +450,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return new SettingsValues(mPrefs, LatinIME.this); } }; - mSettingsValues = job.runInLocale(mResources, mSubtypeSwitcher.getInputLocale()); + mSettingsValues = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale()); mFeedbackManager = new AudioAndHapticFeedbackManager(this, mSettingsValues); resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); } private void initSuggest() { - final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); - final Locale keyboardLocale = mSubtypeSwitcher.getInputLocale(); + final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); + final String localeStr = subtypeLocale.toString(); final Dictionary oldContactsDictionary; if (mSuggest != null) { @@ -504,11 +466,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { oldContactsDictionary = null; } - mSuggest = new Suggest(this, keyboardLocale); + mSuggest = new Suggest(this, subtypeLocale); if (mSettingsValues.mAutoCorrectEnabled) { mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold); } + mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); + mUserDictionary = new UserDictionary(this, localeStr); mSuggest.setUserDictionary(mUserDictionary); mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); @@ -550,7 +514,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { if (USE_BINARY_CONTACTS_DICTIONARY) { dictionaryToUse = new ContactsBinaryDictionary(this, Suggest.DIC_CONTACTS, - mSubtypeSwitcher.getInputLocale()); + mSubtypeSwitcher.getCurrentSubtypeLocale()); } else { dictionaryToUse = new ContactsDictionary(this, Suggest.DIC_CONTACTS); } @@ -562,7 +526,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } /* package private */ void resetSuggestMainDict() { - mSuggest.resetMainDict(this, mSubtypeSwitcher.getInputLocale()); + final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); + mSuggest.resetMainDict(this, subtypeLocale); + mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); } @Override @@ -642,13 +608,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) { - SubtypeSwitcher.getInstance().updateSubtype(subtype); + mSubtypeSwitcher.updateSubtype(subtype); } private void onStartInputInternal(EditorInfo editorInfo, boolean restarting) { super.onStartInput(editorInfo, restarting); } + @SuppressWarnings("deprecation") private void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) { super.onStartInputView(editorInfo, restarting); final KeyboardSwitcher switcher = mKeyboardSwitcher; @@ -669,12 +636,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_onStartInputViewInternal(editorInfo); } - if (StringUtils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { + if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); - Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead"); + Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead"); } - if (StringUtils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) { + if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); @@ -1077,7 +1044,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (ic == null) return false; final CharSequence lastThree = ic.getTextBeforeCursor(3, 0); if (lastThree != null && lastThree.length() == 3 - && StringUtils.canBeFollowedByPeriod(lastThree.charAt(0)) + && canBeFollowedByPeriod(lastThree.charAt(0)) && lastThree.charAt(1) == Keyboard.CODE_SPACE && lastThree.charAt(2) == Keyboard.CODE_SPACE && mHandler.isAcceptingDoubleSpaces()) { @@ -1093,6 +1060,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return false; } + private static boolean canBeFollowedByPeriod(final int codePoint) { + // TODO: Check again whether there really ain't a better way to check this. + // TODO: This should probably be language-dependant... + return Character.isLetterOrDigit(codePoint) + || codePoint == Keyboard.CODE_SINGLE_QUOTE + || codePoint == Keyboard.CODE_DOUBLE_QUOTE + || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS + || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET + || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET + || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; + } + // "ic" may be null private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { if (ic == null) return; @@ -1920,7 +1899,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (mSettingsValues.mEnableSuggestionSpanInsertion) { final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( - this, bestWord, suggestedWords, mSubtypeSwitcher.isDictionaryAvailable()), + this, bestWord, suggestedWords, mIsMainDictionaryAvailable), 1); if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_commitText(bestWord); @@ -1998,7 +1977,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } final String secondWord; if (mWordComposer.isAutoCapitalized() && !mWordComposer.isMostlyCaps()) { - secondWord = suggestion.toString().toLowerCase(mSubtypeSwitcher.getInputLocale()); + secondWord = suggestion.toString().toLowerCase( + mSubtypeSwitcher.getCurrentSubtypeLocale()); } else { secondWord = suggestion.toString(); } @@ -2326,8 +2306,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } private void showOptionDialogInternal(AlertDialog dialog) { - final IBinder windowToken = KeyboardSwitcher.getInstance().getKeyboardView() - .getWindowToken(); + final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken(); if (windowToken == null) return; dialog.setCancelable(true); diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 29825df7d..13264f7e8 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -33,6 +33,7 @@ import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.view.LayoutInflater; import android.view.View; +import android.view.inputmethod.InputMethodSubtype; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; @@ -255,6 +256,7 @@ public class Settings extends InputMethodSettingsFragment } updateShowCorrectionSuggestionsSummary(); updateKeyPreviewPopupDelaySummary(); + updateCustomInputStylesSummary(); } @Override @@ -294,6 +296,21 @@ public class Settings extends InputMethodSettingsFragment mShowCorrectionSuggestionsPreference.getValue())]); } + private void updateCustomInputStylesSummary() { + final PreferenceScreen customInputStyles = + (PreferenceScreen)findPreference(PREF_CUSTOM_INPUT_STYLES); + final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, getResources()); + final InputMethodSubtype[] subtypes = + AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype); + final StringBuilder styles = new StringBuilder(); + for (final InputMethodSubtype subtype : subtypes) { + if (styles.length() > 0) styles.append(", "); + styles.append(SubtypeLocale.getFullDisplayName(subtype)); + } + customInputStyles.setSummary(styles); + } + private void updateKeyPreviewPopupDelaySummary() { final ListPreference lp = mKeyPreviewPopupDismissDelay; lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]); diff --git a/java/src/com/android/inputmethod/latin/SettingsActivity.java b/java/src/com/android/inputmethod/latin/SettingsActivity.java index 556701364..68f8582fc 100644 --- a/java/src/com/android/inputmethod/latin/SettingsActivity.java +++ b/java/src/com/android/inputmethod/latin/SettingsActivity.java @@ -20,11 +20,15 @@ import android.content.Intent; import android.preference.PreferenceActivity; public class SettingsActivity extends PreferenceActivity { + private static final String DEFAULT_FRAGMENT = Settings.class.getName(); + @Override public Intent getIntent() { - final Intent modIntent = new Intent(super.getIntent()); - modIntent.putExtra(EXTRA_SHOW_FRAGMENT, Settings.class.getName()); - modIntent.putExtra(EXTRA_NO_HEADERS, true); - return modIntent; + final Intent intent = super.getIntent(); + if (!intent.hasExtra(EXTRA_SHOW_FRAGMENT)) { + intent.putExtra(EXTRA_SHOW_FRAGMENT, DEFAULT_FRAGMENT); + } + intent.putExtra(EXTRA_NO_HEADERS, true); + return intent; } } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index c160555f0..5f9e1bc76 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -28,7 +28,6 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.util.ArrayList; import java.util.Arrays; -import java.util.Locale; /** * When you call the constructor of this class, you may want to change the current system locale by @@ -148,9 +147,8 @@ public class SettingsValues { mAutoCorrectionThresholdRawValue); mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff); mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain); - mAdditionalSubtypes = AdditionalSubtype.createAdditionalSubtypesArray( - getCsvAdditionalSubtypes(prefs, res)); + getPrefAdditionalSubtypes(prefs, res)); } // Helper functions to create member values. @@ -315,10 +313,10 @@ public class SettingsValues { return mAdditionalSubtypes; } - public static String getCsvAdditionalSubtypes(final SharedPreferences prefs, + public static String getPrefAdditionalSubtypes(final SharedPreferences prefs, final Resources res) { - final String csvPredefinedSubtypes = res.getString(R.string.predefined_subtypes, ""); - return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, csvPredefinedSubtypes); + final String prefSubtypes = res.getString(R.string.predefined_subtypes, ""); + return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes); } // Accessed from the settings interface, hence public diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index a599933d8..160581cbe 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -17,9 +17,6 @@ package com.android.inputmethod.latin; import android.text.TextUtils; -import android.view.inputmethod.EditorInfo; - -import com.android.inputmethod.keyboard.Keyboard; import java.util.ArrayList; import java.util.Locale; @@ -29,39 +26,38 @@ public class StringUtils { // This utility class is not publicly instantiable. } - public static boolean canBeFollowedByPeriod(final int codePoint) { - // TODO: Check again whether there really ain't a better way to check this. - // TODO: This should probably be language-dependant... - return Character.isLetterOrDigit(codePoint) - || codePoint == Keyboard.CODE_SINGLE_QUOTE - || codePoint == Keyboard.CODE_DOUBLE_QUOTE - || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS - || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET - || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET - || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; - } - public static int codePointCount(String text) { if (TextUtils.isEmpty(text)) return 0; return text.codePointCount(0, text.length()); } - private static boolean containsInCsv(String key, String csv) { - if (csv == null) - return false; - for (String option : csv.split(",")) { - if (option.equals(key)) - return true; + public static boolean containsInArray(String key, String[] array) { + for (final String element : array) { + if (key.equals(element)) return true; } return false; } - public static boolean inPrivateImeOptions(String packageName, String key, - EditorInfo editorInfo) { - if (editorInfo == null) - return false; - return containsInCsv(packageName != null ? packageName + "." + key : key, - editorInfo.privateImeOptions); + public static boolean containsInCsv(String key, String csv) { + if (TextUtils.isEmpty(csv)) return false; + return containsInArray(key, csv.split(",")); + } + + public static String appendToCsvIfNotExists(String key, String csv) { + if (TextUtils.isEmpty(csv)) return key; + if (containsInCsv(key, csv)) return csv; + return csv + "," + key; + } + + public static String removeFromCsvIfExists(String key, String csv) { + if (TextUtils.isEmpty(csv)) return ""; + final String[] elements = csv.split(","); + if (!containsInArray(key, elements)) return csv; + final ArrayList<String> result = new ArrayList<String>(elements.length - 1); + for (final String element : elements) { + if (!key.equals(element)) result.add(element); + } + return TextUtils.join(",", result); } /** diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java index 37f46fc79..fc6193287 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java +++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; + import android.content.Context; import android.content.res.Resources; import android.view.inputmethod.InputMethodSubtype; @@ -24,6 +26,8 @@ import java.util.HashMap; import java.util.Locale; public class SubtypeLocale { + private static final String TAG = SubtypeLocale.class.getSimpleName(); + // Special language code to represent "no language". public static final String NO_LANGUAGE = "zz"; @@ -56,26 +60,29 @@ public class SubtypeLocale { // zz qwerty F QWERTY QWERTY // fr qwertz T Fr Français Français (QWERTZ) // de qwerty T De Deutsch Deutsch (QWERTY) - // en azerty T En English English (AZERTY) + // en_US azerty T En English English (US) (AZERTY) // zz azerty T AZERTY AZERTY // Get InputMethodSubtype's full display name in its locale. public static String getFullDisplayName(InputMethodSubtype subtype) { - final String value = sExceptionalDisplayNamesMap.get(subtype.getLocale()); - if (value != null) { - return value; - } - if (isNoLanguage(subtype)) { return getKeyboardLayoutSetDisplayName(subtype); } + final String exceptionalValue = sExceptionalDisplayNamesMap.get(subtype.getLocale()); + final Locale locale = getSubtypeLocale(subtype); - final String language = StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale); if (AdditionalSubtype.isAdditionalSubtype(subtype)) { - return String.format("%s (%s)", - language, getKeyboardLayoutSetDisplayName(subtype)); + final String language = (exceptionalValue != null) ? exceptionalValue + : StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale); + final String layout = getKeyboardLayoutSetDisplayName(subtype); + return String.format("%s (%s)", language, layout); } + + if (exceptionalValue != null) { + return exceptionalValue; + } + return StringUtils.toTitleCase(locale.getDisplayName(locale), locale); } @@ -112,11 +119,14 @@ public class SubtypeLocale { } public static String getKeyboardLayoutSetName(InputMethodSubtype subtype) { - final String keyboardLayoutSet = subtype.getExtraValueOf( - LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET); + final String keyboardLayoutSet = subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET); // TODO: Remove this null check when InputMethodManager.getCurrentInputMethodSubtype is // fixed. - if (keyboardLayoutSet == null) return AdditionalSubtype.QWERTY; + if (keyboardLayoutSet == null) { + android.util.Log.w(TAG, "KeyboardLayoutSet not found, use QWERTY: " + + "locale=" + subtype.getLocale() + " extraValue=" + subtype.getExtraValue()); + return AdditionalSubtype.QWERTY; + } return keyboardLayoutSet; } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index cf95a7e1a..3b9a4069d 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -16,16 +16,16 @@ package com.android.inputmethod.latin; +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.REQ_NETWORK_CONNECTIVITY; + import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.AsyncTask; import android.os.IBinder; -import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -33,7 +33,6 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.keyboard.KeyboardSwitcher; -import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -42,41 +41,42 @@ public class SubtypeSwitcher { private static boolean DBG = LatinImeLogger.sDBG; private static final String TAG = SubtypeSwitcher.class.getSimpleName(); - public static final String KEYBOARD_MODE = "keyboard"; - private static final char LOCALE_SEPARATOR = '_'; - private static final String SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY = - "requireNetworkConnectivity"; - - private final TextUtils.SimpleStringSplitter mLocaleSplitter = - new TextUtils.SimpleStringSplitter(LOCALE_SEPARATOR); - private static final SubtypeSwitcher sInstance = new SubtypeSwitcher(); private /* final */ LatinIME mService; private /* final */ InputMethodManager mImm; private /* final */ Resources mResources; private /* final */ ConnectivityManager mConnectivityManager; - private final ArrayList<InputMethodSubtype> mEnabledKeyboardSubtypesOfCurrentInputMethod = - new ArrayList<InputMethodSubtype>(); - private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>(); /*-----------------------------------------------------------*/ // Variants which should be changed only by reload functions. - private boolean mNeedsToDisplayLanguage; - private boolean mIsDictionaryAvailable; - private boolean mIsSystemLanguageSameAsInputLanguage; + private NeedsToDisplayLanguage mNeedsToDisplayLanguage = new NeedsToDisplayLanguage(); private InputMethodInfo mShortcutInputMethodInfo; private InputMethodSubtype mShortcutSubtype; - private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod; private InputMethodSubtype mNoLanguageSubtype; // Note: This variable is always non-null after {@link #initialize(LatinIME)}. private InputMethodSubtype mCurrentSubtype; - private Locale mSystemLocale; - private Locale mInputLocale; - private String mInputLocaleStr; + private Locale mCurrentSystemLocale; /*-----------------------------------------------------------*/ private boolean mIsNetworkConnected; + static class NeedsToDisplayLanguage { + private int mEnabledSubtypeCount; + private boolean mIsSystemLanguageSameAsInputLanguage; + + public boolean getValue() { + return mEnabledSubtypeCount >= 2 || !mIsSystemLanguageSameAsInputLanguage; + } + + public void updateEnabledSubtypeCount(int count) { + mEnabledSubtypeCount = count; + } + + public void updateIsSystemLanguageSameAsInputLanguage(boolean isSame) { + mIsSystemLanguageSameAsInputLanguage = isSame; + } + } + public static SubtypeSwitcher getInstance() { return sInstance; } @@ -97,13 +97,8 @@ public class SubtypeSwitcher { mImm = ImfUtils.getInputMethodManager(service); mConnectivityManager = (ConnectivityManager) service.getSystemService( Context.CONNECTIVITY_SERVICE); - mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); - mEnabledLanguagesOfCurrentInputMethod.clear(); - mSystemLocale = null; - mInputLocale = null; - mInputLocaleStr = null; + mCurrentSystemLocale = mResources.getConfiguration().locale; mCurrentSubtype = mImm.getCurrentInputMethodSubtype(); - mAllEnabledSubtypesOfCurrentInputMethod = null; mNoLanguageSubtype = ImfUtils.findSubtypeByLocaleAndKeyboardLayoutSet( service, SubtypeLocale.NO_LANGUAGE, AdditionalSubtype.QWERTY); @@ -114,7 +109,7 @@ public class SubtypeSwitcher { // Update all parameters stored in SubtypeSwitcher. // Only configuration changed event is allowed to call this because this is heavy. private void updateAllParameters() { - mSystemLocale = mResources.getConfiguration().locale; + mCurrentSystemLocale = mResources.getConfiguration().locale; updateSubtype(mImm.getCurrentInputMethodSubtype()); updateParametersOnStartInputView(); } @@ -128,31 +123,20 @@ public class SubtypeSwitcher { // Reload enabledSubtypes from the framework. private void updateEnabledSubtypes() { - final String currentMode = mCurrentSubtype.getMode(); + final InputMethodSubtype currentSubtype = mCurrentSubtype; boolean foundCurrentSubtypeBecameDisabled = true; - mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList( - null, true); - mEnabledLanguagesOfCurrentInputMethod.clear(); - mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); - for (InputMethodSubtype ims : mAllEnabledSubtypesOfCurrentInputMethod) { - final String locale = ims.getLocale(); - final String mode = ims.getMode(); - mLocaleSplitter.setString(locale); - if (mLocaleSplitter.hasNext()) { - mEnabledLanguagesOfCurrentInputMethod.add(mLocaleSplitter.next()); - } - if (locale.equals(mInputLocaleStr) && mode.equals(currentMode)) { + final List<InputMethodSubtype> enabledSubtypesOfThisIme = + mImm.getEnabledInputMethodSubtypeList(null, true); + for (InputMethodSubtype ims : enabledSubtypesOfThisIme) { + if (ims.equals(currentSubtype)) { foundCurrentSubtypeBecameDisabled = false; } - if (KEYBOARD_MODE.equals(ims.getMode())) { - mEnabledKeyboardSubtypesOfCurrentInputMethod.add(ims); - } } - mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1 - && mIsSystemLanguageSameAsInputLanguage); + mNeedsToDisplayLanguage.updateEnabledSubtypeCount(enabledSubtypesOfThisIme.size()); if (foundCurrentSubtypeBecameDisabled) { if (DBG) { - Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + currentMode); + Log.w(TAG, "Last subtype: " + + currentSubtype.getLocale() + "/" + currentSubtype.getExtraValue()); Log.w(TAG, "Last subtype was disabled. Update to the current one."); } updateSubtype(mImm.getCurrentInputMethodSubtype()); @@ -193,70 +177,20 @@ public class SubtypeSwitcher { // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. public void updateSubtype(InputMethodSubtype newSubtype) { - final String newLocale = newSubtype.getLocale(); - final String newMode = newSubtype.getMode(); - final String oldMode = mCurrentSubtype.getMode(); if (DBG) { - Log.w(TAG, "Update subtype to:" + newLocale + "," + newMode - + ", from: " + mInputLocaleStr + ", " + oldMode); - } - boolean languageChanged = false; - if (!newLocale.equals(mInputLocaleStr)) { - if (mInputLocaleStr != null) { - languageChanged = true; - } - updateInputLocale(newLocale); + Log.w(TAG, "onCurrentInputMethodSubtypeChanged: to: " + + newSubtype.getLocale() + "/" + newSubtype.getExtraValue() + ", from: " + + mCurrentSubtype.getLocale() + "/" + mCurrentSubtype.getExtraValue()); } - boolean modeChanged = false; - if (!newMode.equals(oldMode)) { - if (oldMode != null) { - modeChanged = true; - } - } - mCurrentSubtype = newSubtype; + if (newSubtype.equals(mCurrentSubtype)) return; - if (KEYBOARD_MODE.equals(mCurrentSubtype.getMode())) { - if (modeChanged || languageChanged) { - updateShortcutIME(); - mService.onRefreshKeyboard(); - } - } else { - final String packageName = mService.getPackageName(); - int version = -1; - try { - version = mService.getPackageManager().getPackageInfo( - packageName, 0).versionCode; - } catch (NameNotFoundException e) { - } - Log.w(TAG, "Unknown subtype mode: " + newMode + "," + version + ", " + packageName - + ". IME is already changed to other IME."); - Log.w(TAG, "Subtype mode:" + newSubtype.getMode()); - Log.w(TAG, "Subtype locale:" + newSubtype.getLocale()); - Log.w(TAG, "Subtype extra value:" + newSubtype.getExtraValue()); - Log.w(TAG, "Subtype is auxiliary:" + newSubtype.isAuxiliary()); - } - } + final Locale newLocale = SubtypeLocale.getSubtypeLocale(newSubtype); + mNeedsToDisplayLanguage.updateIsSystemLanguageSameAsInputLanguage( + mCurrentSystemLocale.equals(newLocale)); - // Update the current input locale from Locale string. - private void updateInputLocale(String inputLocaleStr) { - // example: inputLocaleStr = "en_US" "en" "" - // "en_US" --> language: en & country: US - // "en" --> language: en - // "" --> the system locale - if (!TextUtils.isEmpty(inputLocaleStr)) { - mInputLocale = LocaleUtils.constructLocaleFromString(inputLocaleStr); - mInputLocaleStr = inputLocaleStr; - } else { - mInputLocale = mSystemLocale; - String country = mSystemLocale.getCountry(); - mInputLocaleStr = mSystemLocale.getLanguage() - + (TextUtils.isEmpty(country) ? "" : "_" + mSystemLocale.getLanguage()); - } - mIsSystemLanguageSameAsInputLanguage = getSystemLocale().getLanguage().equalsIgnoreCase( - getInputLocale().getLanguage()); - mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1 - && mIsSystemLanguageSameAsInputLanguage); - mIsDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(mService, mInputLocale); + mCurrentSubtype = newSubtype; + updateShortcutIME(); + mService.onRefreshKeyboard(); } //////////////////////////// @@ -309,8 +243,7 @@ public class SubtypeSwitcher { return false; if (mShortcutSubtype == null) return true; - if (mShortcutSubtype.containsExtraValueKey( - SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY)) { + if (mShortcutSubtype.containsExtraValueKey(REQ_NETWORK_CONNECTIVITY)) { return mIsNetworkConnected; } return true; @@ -325,62 +258,31 @@ public class SubtypeSwitcher { } ////////////////////////////////// - // Language Switching functions // + // Subtype Switching functions // ////////////////////////////////// - public int getEnabledKeyboardLocaleCount() { - return mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); - } - public boolean needsToDisplayLanguage(Locale keyboardLocale) { if (keyboardLocale.toString().equals(SubtypeLocale.NO_LANGUAGE)) { return true; } - if (!keyboardLocale.equals(mInputLocale)) { + if (!keyboardLocale.equals(getCurrentSubtypeLocale())) { return false; } - return mNeedsToDisplayLanguage; - } - - public Locale getInputLocale() { - return mInputLocale; + return mNeedsToDisplayLanguage.getValue(); } - public String getInputLocaleStr() { - return mInputLocaleStr; - } - - public String[] getEnabledLanguages() { - int enabledLanguageCount = mEnabledLanguagesOfCurrentInputMethod.size(); - // Workaround for explicitly specifying the voice language - if (enabledLanguageCount == 1) { - mEnabledLanguagesOfCurrentInputMethod.add(mEnabledLanguagesOfCurrentInputMethod - .get(0)); - ++enabledLanguageCount; - } - return mEnabledLanguagesOfCurrentInputMethod.toArray(new String[enabledLanguageCount]); - } - - public Locale getSystemLocale() { - return mSystemLocale; - } - - public boolean isSystemLanguageSameAsInputLanguage() { - return mIsSystemLanguageSameAsInputLanguage; + public Locale getCurrentSubtypeLocale() { + return SubtypeLocale.getSubtypeLocale(mCurrentSubtype); } public void onConfigurationChanged(Configuration conf) { final Locale systemLocale = conf.locale; // If system configuration was changed, update all parameters. - if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) { + if (!systemLocale.equals(mCurrentSystemLocale)) { updateAllParameters(); } } - public boolean isDictionaryAvailable() { - return mIsDictionaryAvailable; - } - public InputMethodSubtype getCurrentSubtype() { return mCurrentSubtype; } |