From 7a39bd4454664b5c37b30e9b5362ddbcdce3b374 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 7 Feb 2012 17:07:23 +0900 Subject: [PATCH] Shift+Smiley key will register newline character of textMultiLine This change also * Honors the custom action label in EditorInfo.actionLabel. * Invokes InputConnection.performeEditorAction if action is specifed at EditorInfo.imeOptions or actionLabel/actionId. * Stops using InputMethodService.sendKeyChar. Implements sendKeyCodePoint instead. Bug: 2498607 Bug: 5961809 Bug: 5368408 Change-Id: If4cd5eb3dacfc6b6a7ea434b0617c2438e06e42d --- java/res/values/attrs.xml | 11 +- java/res/values/keycodes.xml | 9 +- java/res/values/strings.xml | 2 + java/res/xml-sw600dp/key_styles_common.xml | 8 +- java/res/xml-sw600dp/row_qwerty2.xml | 2 +- java/res/xml-sw600dp/rows_arabic.xml | 2 +- java/res/xml-sw600dp/rows_azerty.xml | 2 +- java/res/xml-sw600dp/rows_bulgarian.xml | 2 +- java/res/xml-sw600dp/rows_hebrew.xml | 2 +- java/res/xml-sw600dp/rows_number_normal.xml | 2 +- java/res/xml-sw600dp/rows_number_password.xml | 2 +- java/res/xml-sw600dp/rows_phone.xml | 2 +- java/res/xml-sw600dp/rows_scandinavian.xml | 2 +- java/res/xml-sw600dp/rows_serbian.xml | 2 +- java/res/xml-sw600dp/rows_slavic.xml | 2 +- java/res/xml-sw600dp/rows_spanish.xml | 2 +- java/res/xml-sw600dp/rows_symbols.xml | 2 +- java/res/xml-sw600dp/rows_symbols_shift.xml | 2 +- java/res/xml-sw768dp/key_styles_common.xml | 8 +- java/res/xml-sw768dp/row_qwerty2.xml | 2 +- java/res/xml-sw768dp/rows_arabic.xml | 2 +- java/res/xml-sw768dp/rows_azerty.xml | 2 +- java/res/xml-sw768dp/rows_bulgarian.xml | 2 +- java/res/xml-sw768dp/rows_hebrew.xml | 2 +- java/res/xml-sw768dp/rows_number_normal.xml | 2 +- java/res/xml-sw768dp/rows_number_password.xml | 2 +- java/res/xml-sw768dp/rows_phone.xml | 2 +- java/res/xml-sw768dp/rows_scandinavian.xml | 2 +- java/res/xml-sw768dp/rows_serbian.xml | 2 +- java/res/xml-sw768dp/rows_slavic.xml | 2 +- java/res/xml-sw768dp/rows_spanish.xml | 2 +- java/res/xml-sw768dp/rows_symbols.xml | 2 +- java/res/xml-sw768dp/rows_symbols_shift.xml | 2 +- java/res/xml/key_styles_common.xml | 95 +---------- java/res/xml/key_styles_enter_phone.xml | 124 ++++++++++++++ java/res/xml/key_styles_enter_tablet.xml | 111 +++++++++++++ java/res/xml/row_qwerty4.xml | 4 +- java/res/xml/row_symbols4.xml | 4 +- java/res/xml/row_symbols_shift4.xml | 4 +- java/res/xml/rows_number_normal.xml | 2 +- java/res/xml/rows_number_password.xml | 2 +- java/res/xml/rows_phone.xml | 2 +- java/res/xml/rows_phone_symbols.xml | 2 +- .../compat/EditorInfoCompatUtils.java | 58 +++---- .../com/android/inputmethod/keyboard/Key.java | 21 ++- .../inputmethod/keyboard/Keyboard.java | 156 +++++++++++------- .../inputmethod/keyboard/KeyboardId.java | 49 ++++-- .../inputmethod/keyboard/KeyboardSet.java | 18 +- .../android/inputmethod/latin/LatinIME.java | 52 +++++- 49 files changed, 515 insertions(+), 283 deletions(-) create mode 100644 java/res/xml/key_styles_enter_phone.xml create mode 100644 java/res/xml/key_styles_enter_tablet.xml diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 86e3fe3cb..2dea8fbb4 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -232,10 +232,7 @@ been replaced, those remaining entries are appended at the end of moreKeys. --> - - - - + @@ -281,10 +278,13 @@ + + + @@ -368,6 +368,7 @@ + @@ -378,6 +379,8 @@ + + diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml index 2a91a3d6d..d552b9349 100644 --- a/java/res/values/keycodes.xml +++ b/java/res/values/keycodes.xml @@ -25,9 +25,10 @@ 32 -1 -2 - -4 - -5 - -6 - -7 + -3 + -4 + -5 + -6 + -7 -9 diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index d64059f33..089acf379 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -128,6 +128,8 @@ Go Next + + Prev Done diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml index b55414786..81334c9e9 100644 --- a/java/res/xml-sw600dp/key_styles_common.xml +++ b/java/res/xml-sw600dp/key_styles_common.xml @@ -89,12 +89,8 @@ latin:keyIcon="iconDeleteKey" latin:keyActionFlags="isRepeatable|noKeyPreview" latin:backgroundType="functional" /> - + diff --git a/java/res/xml-sw600dp/rows_arabic.xml b/java/res/xml-sw600dp/rows_arabic.xml index 8d4901be3..1f03968ee 100644 --- a/java/res/xml-sw600dp/rows_arabic.xml +++ b/java/res/xml-sw600dp/rows_arabic.xml @@ -138,7 +138,7 @@ diff --git a/java/res/xml-sw600dp/rows_azerty.xml b/java/res/xml-sw600dp/rows_azerty.xml index aabe6b0e8..5c799623d 100644 --- a/java/res/xml-sw600dp/rows_azerty.xml +++ b/java/res/xml-sw600dp/rows_azerty.xml @@ -90,7 +90,7 @@ diff --git a/java/res/xml-sw600dp/rows_bulgarian.xml b/java/res/xml-sw600dp/rows_bulgarian.xml index b464158f0..7a23ce9ff 100644 --- a/java/res/xml-sw600dp/rows_bulgarian.xml +++ b/java/res/xml-sw600dp/rows_bulgarian.xml @@ -80,7 +80,7 @@ diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml index f7eb9505a..3141bbdc7 100644 --- a/java/res/xml-sw600dp/rows_number_normal.xml +++ b/java/res/xml-sw600dp/rows_number_normal.xml @@ -78,7 +78,7 @@ latin:keyLabel="6" latin:keyStyle="numKeyStyle" /> diff --git a/java/res/xml-sw600dp/rows_number_password.xml b/java/res/xml-sw600dp/rows_number_password.xml index c3f21e106..0a71f74d7 100644 --- a/java/res/xml-sw600dp/rows_number_password.xml +++ b/java/res/xml-sw600dp/rows_number_password.xml @@ -47,7 +47,7 @@ diff --git a/java/res/xml-sw600dp/rows_phone.xml b/java/res/xml-sw600dp/rows_phone.xml index fe8511988..d61b4b2ad 100644 --- a/java/res/xml-sw600dp/rows_phone.xml +++ b/java/res/xml-sw600dp/rows_phone.xml @@ -75,7 +75,7 @@ diff --git a/java/res/xml-sw600dp/rows_scandinavian.xml b/java/res/xml-sw600dp/rows_scandinavian.xml index 5ecb7d242..912c40658 100644 --- a/java/res/xml-sw600dp/rows_scandinavian.xml +++ b/java/res/xml-sw600dp/rows_scandinavian.xml @@ -95,7 +95,7 @@ latin:keyLabel="@string/keylabel_for_scandinavia_row2_11" latin:moreKeys="@string/more_keys_for_scandinavia_row2_11" /> diff --git a/java/res/xml-sw600dp/rows_serbian.xml b/java/res/xml-sw600dp/rows_serbian.xml index c21fd4cb7..ea4bb1466 100644 --- a/java/res/xml-sw600dp/rows_serbian.xml +++ b/java/res/xml-sw600dp/rows_serbian.xml @@ -80,7 +80,7 @@ diff --git a/java/res/xml-sw600dp/rows_slavic.xml b/java/res/xml-sw600dp/rows_slavic.xml index 889a438b5..020ea16a2 100644 --- a/java/res/xml-sw600dp/rows_slavic.xml +++ b/java/res/xml-sw600dp/rows_slavic.xml @@ -87,7 +87,7 @@ diff --git a/java/res/xml-sw600dp/rows_spanish.xml b/java/res/xml-sw600dp/rows_spanish.xml index b516bebfb..2ab94e8c5 100644 --- a/java/res/xml-sw600dp/rows_spanish.xml +++ b/java/res/xml-sw600dp/rows_spanish.xml @@ -56,7 +56,7 @@ diff --git a/java/res/xml-sw600dp/rows_symbols.xml b/java/res/xml-sw600dp/rows_symbols.xml index c2dfe2f82..ce6e539a5 100644 --- a/java/res/xml-sw600dp/rows_symbols.xml +++ b/java/res/xml-sw600dp/rows_symbols.xml @@ -98,7 +98,7 @@ diff --git a/java/res/xml-sw600dp/rows_symbols_shift.xml b/java/res/xml-sw600dp/rows_symbols_shift.xml index 6a640c06b..a10d1740c 100644 --- a/java/res/xml-sw600dp/rows_symbols_shift.xml +++ b/java/res/xml-sw600dp/rows_symbols_shift.xml @@ -80,7 +80,7 @@ diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml index 0d2ac5d12..f01f34969 100644 --- a/java/res/xml-sw768dp/key_styles_common.xml +++ b/java/res/xml-sw768dp/key_styles_common.xml @@ -71,12 +71,8 @@ latin:keyIcon="iconDeleteKey" latin:keyActionFlags="isRepeatable|noKeyPreview" latin:backgroundType="functional" /> - + diff --git a/java/res/xml-sw768dp/rows_arabic.xml b/java/res/xml-sw768dp/rows_arabic.xml index 0e4aee4eb..baced66c3 100644 --- a/java/res/xml-sw768dp/rows_arabic.xml +++ b/java/res/xml-sw768dp/rows_arabic.xml @@ -144,7 +144,7 @@ diff --git a/java/res/xml-sw768dp/rows_azerty.xml b/java/res/xml-sw768dp/rows_azerty.xml index b9ef89822..6023e984b 100644 --- a/java/res/xml-sw768dp/rows_azerty.xml +++ b/java/res/xml-sw768dp/rows_azerty.xml @@ -97,7 +97,7 @@ diff --git a/java/res/xml-sw768dp/rows_bulgarian.xml b/java/res/xml-sw768dp/rows_bulgarian.xml index 57f39b420..d67a0d1fa 100644 --- a/java/res/xml-sw768dp/rows_bulgarian.xml +++ b/java/res/xml-sw768dp/rows_bulgarian.xml @@ -86,7 +86,7 @@ diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml index 0e80e8043..cf947abd2 100644 --- a/java/res/xml-sw768dp/rows_number_normal.xml +++ b/java/res/xml-sw768dp/rows_number_normal.xml @@ -80,7 +80,7 @@ latin:keyLabel="6" latin:keyStyle="numKeyStyle" /> diff --git a/java/res/xml-sw768dp/rows_number_password.xml b/java/res/xml-sw768dp/rows_number_password.xml index 77fb9caac..8acfac6ff 100644 --- a/java/res/xml-sw768dp/rows_number_password.xml +++ b/java/res/xml-sw768dp/rows_number_password.xml @@ -49,7 +49,7 @@ diff --git a/java/res/xml-sw768dp/rows_phone.xml b/java/res/xml-sw768dp/rows_phone.xml index 789c02c42..0404bb1fb 100644 --- a/java/res/xml-sw768dp/rows_phone.xml +++ b/java/res/xml-sw768dp/rows_phone.xml @@ -78,7 +78,7 @@ diff --git a/java/res/xml-sw768dp/rows_scandinavian.xml b/java/res/xml-sw768dp/rows_scandinavian.xml index 9e5ad148f..437316699 100644 --- a/java/res/xml-sw768dp/rows_scandinavian.xml +++ b/java/res/xml-sw768dp/rows_scandinavian.xml @@ -102,7 +102,7 @@ latin:keyLabel="@string/keylabel_for_scandinavia_row2_11" latin:moreKeys="@string/more_keys_for_scandinavia_row2_11" /> diff --git a/java/res/xml-sw768dp/rows_serbian.xml b/java/res/xml-sw768dp/rows_serbian.xml index 2e9e1405d..665975583 100644 --- a/java/res/xml-sw768dp/rows_serbian.xml +++ b/java/res/xml-sw768dp/rows_serbian.xml @@ -114,7 +114,7 @@ diff --git a/java/res/xml-sw768dp/rows_slavic.xml b/java/res/xml-sw768dp/rows_slavic.xml index 86b4498ff..58d5a75fc 100644 --- a/java/res/xml-sw768dp/rows_slavic.xml +++ b/java/res/xml-sw768dp/rows_slavic.xml @@ -92,7 +92,7 @@ diff --git a/java/res/xml-sw768dp/rows_spanish.xml b/java/res/xml-sw768dp/rows_spanish.xml index f626a451f..864c435a2 100644 --- a/java/res/xml-sw768dp/rows_spanish.xml +++ b/java/res/xml-sw768dp/rows_spanish.xml @@ -59,7 +59,7 @@ diff --git a/java/res/xml-sw768dp/rows_symbols.xml b/java/res/xml-sw768dp/rows_symbols.xml index 2ba935724..c199ae404 100644 --- a/java/res/xml-sw768dp/rows_symbols.xml +++ b/java/res/xml-sw768dp/rows_symbols.xml @@ -105,7 +105,7 @@ diff --git a/java/res/xml-sw768dp/rows_symbols_shift.xml b/java/res/xml-sw768dp/rows_symbols_shift.xml index aba9c236d..e88f78633 100644 --- a/java/res/xml-sw768dp/rows_symbols_shift.xml +++ b/java/res/xml-sw768dp/rows_symbols_shift.xml @@ -87,7 +87,7 @@ diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml index 177a62c58..97e06df8d 100644 --- a/java/res/xml/key_styles_common.xml +++ b/java/res/xml/key_styles_common.xml @@ -98,99 +98,8 @@ latin:keyIcon="iconDeleteKey" latin:keyActionFlags="isRepeatable|noKeyPreview" latin:backgroundType="functional" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/res/xml/key_styles_enter_tablet.xml b/java/res/xml/key_styles_enter_tablet.xml new file mode 100644 index 000000000..e54de297e --- /dev/null +++ b/java/res/xml/key_styles_enter_tablet.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml index 65500a653..8c20a72dc 100644 --- a/java/res/xml/row_qwerty4.xml +++ b/java/res/xml/row_qwerty4.xml @@ -40,7 +40,7 @@ @@ -59,7 +59,7 @@ latin:keyStyle="punctuationKeyStyle" latin:keyWidth="9.2%p" /> diff --git a/java/res/xml/row_symbols4.xml b/java/res/xml/row_symbols4.xml index 8b094dd7e..be0c94ffa 100644 --- a/java/res/xml/row_symbols4.xml +++ b/java/res/xml/row_symbols4.xml @@ -40,7 +40,7 @@ @@ -59,7 +59,7 @@ latin:keyStyle="punctuationKeyStyle" latin:keyWidth="9.2%p" /> diff --git a/java/res/xml/row_symbols_shift4.xml b/java/res/xml/row_symbols_shift4.xml index 4e13ac704..dd13b7175 100644 --- a/java/res/xml/row_symbols_shift4.xml +++ b/java/res/xml/row_symbols_shift4.xml @@ -45,7 +45,7 @@ latin:keyLabel="…" latin:backgroundType="functional" /> @@ -70,7 +70,7 @@ latin:keyWidth="9.2%p" latin:backgroundType="functional" /> diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml index 054b564b0..b581fb5cd 100644 --- a/java/res/xml/rows_number_normal.xml +++ b/java/res/xml/rows_number_normal.xml @@ -75,7 +75,7 @@ latin:keyLabel="." latin:keyStyle="numKeyStyle" /> diff --git a/java/res/xml/rows_number_password.xml b/java/res/xml/rows_number_password.xml index ebc13c6a0..e4272ed3f 100644 --- a/java/res/xml/rows_number_password.xml +++ b/java/res/xml/rows_number_password.xml @@ -56,7 +56,7 @@ latin:keyStyle="num0KeyStyle" /> diff --git a/java/res/xml/rows_phone.xml b/java/res/xml/rows_phone.xml index 18e4c9d3e..60296d061 100644 --- a/java/res/xml/rows_phone.xml +++ b/java/res/xml/rows_phone.xml @@ -68,7 +68,7 @@ diff --git a/java/res/xml/rows_phone_symbols.xml b/java/res/xml/rows_phone_symbols.xml index dfa134946..7841c56e5 100644 --- a/java/res/xml/rows_phone_symbols.xml +++ b/java/res/xml/rows_phone_symbols.xml @@ -78,7 +78,7 @@ diff --git a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java index e1db36088..3247997f6 100644 --- a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java @@ -67,42 +67,34 @@ public class EditorInfoCompatUtils { ic.performEditorAction(OBJ_IME_ACTION_PREVIOUS); } - public static String imeOptionsName(int imeOptions) { - if (imeOptions == -1) - return null; + public static String imeActionName(int imeOptions) { final int actionId = imeOptions & EditorInfo.IME_MASK_ACTION; - final String action; switch (actionId) { - case EditorInfo.IME_ACTION_UNSPECIFIED: - action = "actionUnspecified"; - break; - case EditorInfo.IME_ACTION_NONE: - action = "actionNone"; - break; - case EditorInfo.IME_ACTION_GO: - action = "actionGo"; - break; - case EditorInfo.IME_ACTION_SEARCH: - action = "actionSearch"; - break; - case EditorInfo.IME_ACTION_SEND: - action = "actionSend"; - break; - case EditorInfo.IME_ACTION_NEXT: - action = "actionNext"; - break; - case EditorInfo.IME_ACTION_DONE: - action = "actionDone"; - break; - default: { - if (OBJ_IME_ACTION_PREVIOUS != null && actionId == OBJ_IME_ACTION_PREVIOUS) { - action = "actionPrevious"; - } else { - action = "actionUnknown(" + actionId + ")"; - } - break; + case EditorInfo.IME_ACTION_UNSPECIFIED: + return "actionUnspecified"; + case EditorInfo.IME_ACTION_NONE: + return "actionNone"; + case EditorInfo.IME_ACTION_GO: + return "actionGo"; + case EditorInfo.IME_ACTION_SEARCH: + return "actionSearch"; + case EditorInfo.IME_ACTION_SEND: + return "actionSend"; + case EditorInfo.IME_ACTION_NEXT: + return "actionNext"; + case EditorInfo.IME_ACTION_DONE: + return "actionDone"; + default: + if (OBJ_IME_ACTION_PREVIOUS != null && actionId == OBJ_IME_ACTION_PREVIOUS) { + return "actionPrevious"; + } else { + return "actionUnknown(" + actionId + ")"; } } + } + + public static String imeOptionsName(int imeOptions) { + final String action = imeActionName(imeOptions); final StringBuilder flags = new StringBuilder(); if ((imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { flags.append("flagNoEnterAction|"); @@ -116,6 +108,6 @@ public class EditorInfoCompatUtils { if (hasFlagForceAscii(imeOptions)) { flags.append("flagForceAscii|"); } - return flags + action; + return (action != null) ? flags + action : flags.toString(); } } diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 5656c38b4..b90d45d3b 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -72,6 +72,7 @@ public class Key { private static final int LABEL_FLAGS_AUTO_X_SCALE = 0x4000; private static final int LABEL_FLAGS_PRESERVE_CASE = 0x8000; private static final int LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED = 0x10000; + private static final int LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL = 0x20000; /** Icon to display instead of a label. Icon takes precedence over a label */ private final int mIconId; @@ -247,14 +248,18 @@ public class Key { mMaxMoreKeysColumn = style.getInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn); - mLabel = adjustCaseOfStringForKeyboardId(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId); - mHintLabel = adjustCaseOfStringForKeyboardId(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyHintLabel), preserveCase, params.mId); - String outputText = adjustCaseOfStringForKeyboardId(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyOutputText), preserveCase, params.mId); - final int code = style.getInt(keyAttr, - R.styleable.Keyboard_Key_code, Keyboard.CODE_UNSPECIFIED); + if ((mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0) { + mLabel = params.mId.mCustomActionLabel; + } else { + mLabel = adjustCaseOfStringForKeyboardId(style.getString( + keyAttr, R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId); + } + mHintLabel = adjustCaseOfStringForKeyboardId(style.getString( + keyAttr, R.styleable.Keyboard_Key_keyHintLabel), preserveCase, params.mId); + String outputText = adjustCaseOfStringForKeyboardId(style.getString( + keyAttr, R.styleable.Keyboard_Key_keyOutputText), preserveCase, params.mId); + final int code = style.getInt( + keyAttr, R.styleable.Keyboard_Key_code, Keyboard.CODE_UNSPECIFIED); // Choose the first letter of the label as primary code if not specified. if (code == Keyboard.CODE_UNSPECIFIED && TextUtils.isEmpty(outputText) && !TextUtils.isEmpty(mLabel)) { diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index cb6a54569..28f71f443 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -28,7 +28,6 @@ import android.util.TypedValue; import android.util.Xml; import android.view.InflateException; -import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.keyboard.internal.KeyStyles; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.latin.LatinImeLogger; @@ -95,10 +94,11 @@ public class Keyboard { */ public static final int CODE_SHIFT = -1; public static final int CODE_SWITCH_ALPHA_SYMBOL = -2; - public static final int CODE_OUTPUT_TEXT = -4; - public static final int CODE_DELETE = -5; - public static final int CODE_SETTINGS = -6; - public static final int CODE_SHORTCUT = -7; + public static final int CODE_OUTPUT_TEXT = -3; + public static final int CODE_DELETE = -4; + public static final int CODE_SETTINGS = -5; + public static final int CODE_SHORTCUT = -6; + public static final int CODE_ACTION_ENTER = -7; // Code value representing the code is not specified. public static final int CODE_UNSPECIFIED = -9; @@ -380,6 +380,7 @@ public class Keyboard { case CODE_DELETE: return "delete"; case CODE_SETTINGS: return "settings"; case CODE_SHORTCUT: return "shortcut"; + case CODE_ACTION_ENTER: return "actionEnter"; case CODE_UNSPECIFIED: return "unspec"; case CODE_TAB: return "tab"; case CODE_ENTER: return "enter"; @@ -475,7 +476,7 @@ public class Keyboard { */ public static class Builder { - private static final String TAG = Builder.class.getSimpleName(); + private static final String BUILDER_TAG = "Keyboard.Builder"; private static final boolean DEBUG = false; // Keyboard XML Tags @@ -643,7 +644,7 @@ public class Keyboard { a.recycle(); if (resourceId == 0) { if (LatinImeLogger.sDBG) - Log.e(TAG, "touchPositionCorrectionData is not defined"); + Log.e(BUILDER_TAG, "touchPositionCorrectionData is not defined"); return; } @@ -680,10 +681,10 @@ public class Keyboard { try { parseKeyboard(parser); } catch (XmlPullParserException e) { - Log.w(TAG, "keyboard XML parse error: " + e); + Log.w(BUILDER_TAG, "keyboard XML parse error: " + e); throw new IllegalArgumentException(e); } catch (IOException e) { - Log.w(TAG, "keyboard XML parse error: " + e); + Log.w(BUILDER_TAG, "keyboard XML parse error: " + e); throw new RuntimeException(e); } finally { parser.close(); @@ -699,9 +700,29 @@ public class Keyboard { return new Keyboard(mParams); } + private int mIndent; + private static final String SPACES = " "; + + private static String spaces(int count) { + return (count < SPACES.length()) ? SPACES.substring(0, count) : SPACES; + } + + private void startTag(String format, Object ... args) { + Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args)); + } + + private void endTag(String format, Object ... args) { + Log.d(BUILDER_TAG, String.format(spaces(mIndent-- * 2) + format, args)); + } + + private void startEndTag(String format, Object ... args) { + Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args)); + mIndent--; + } + private void parseKeyboard(XmlPullParser parser) throws XmlPullParserException, IOException { - if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mParams.mId)); + if (DEBUG) startTag("<%s> %s", TAG_KEYBOARD, mParams.mId); int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { @@ -788,9 +809,10 @@ public class Keyboard { final String tag = parser.getName(); if (TAG_ROW.equals(tag)) { Row row = parseRowAttributes(parser); - if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW)); - if (!skip) + if (DEBUG) startTag("<%s>%s", TAG_ROW, skip ? " skipped" : ""); + if (!skip) { startRow(row); + } parseRowContent(parser, row, skip); } else if (TAG_INCLUDE.equals(tag)) { parseIncludeKeyboardContent(parser, skip); @@ -803,15 +825,13 @@ public class Keyboard { } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); + if (DEBUG) endTag("", tag); if (TAG_KEYBOARD.equals(tag)) { endKeyboard(); break; } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) || TAG_MERGE.equals(tag)) { - if (DEBUG) Log.d(TAG, String.format("", tag)); break; - } else if (TAG_KEY_STYLE.equals(tag)) { - continue; } else { throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW); } @@ -854,17 +874,15 @@ public class Keyboard { } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); + if (DEBUG) endTag("", tag); if (TAG_ROW.equals(tag)) { - if (DEBUG) Log.d(TAG, String.format("", TAG_ROW)); - if (!skip) + if (!skip) { endRow(row); + } break; } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) || TAG_MERGE.equals(tag)) { - if (DEBUG) Log.d(TAG, String.format("", tag)); break; - } else if (TAG_KEY_STYLE.equals(tag)) { - continue; } else { throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); } @@ -876,11 +894,14 @@ public class Keyboard { throws XmlPullParserException, IOException { if (skip) { XmlParseUtils.checkEndTag(TAG_KEY, parser); + if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY); } else { final Key key = new Key(mResources, mParams, row, parser, mKeyStyles); - if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />", - TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode, - Arrays.toString(key.mMoreKeys))); + if (DEBUG) { + startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY, + (key.isEnabled() ? "" : " disabled"), key, + Arrays.toString(key.mMoreKeys)); + } XmlParseUtils.checkEndTag(TAG_KEY, parser); endKey(key); } @@ -890,10 +911,11 @@ public class Keyboard { throws XmlPullParserException, IOException { if (skip) { XmlParseUtils.checkEndTag(TAG_SPACER, parser); + if (DEBUG) startEndTag("<%s /> skipped", TAG_SPACER); } else { final Key.Spacer spacer = new Key.Spacer( mResources, mParams, row, parser, mKeyStyles); - if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER)); + if (DEBUG) startEndTag("<%s />", TAG_SPACER); XmlParseUtils.checkEndTag(TAG_SPACER, parser); endKey(spacer); } @@ -913,6 +935,7 @@ public class Keyboard { throws XmlPullParserException, IOException { if (skip) { XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); + if (DEBUG) startEndTag(" skipped", TAG_INCLUDE); } else { final AttributeSet attr = Xml.asAttributeSet(parser); final TypedArray keyboardAttr = mResources.obtainAttributes(attr, @@ -944,8 +967,10 @@ public class Keyboard { } XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); - if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />", - TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout))); + if (DEBUG) { + startEndTag("<%s keyboardLayout=%s />",TAG_INCLUDE, + mResources.getResourceEntryName(keyboardLayout)); + } final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout); try { parseMerge(parserForInclude, row, skip); @@ -961,6 +986,7 @@ public class Keyboard { private void parseMerge(XmlPullParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { + if (DEBUG) startTag("<%s>", TAG_MERGE); int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { @@ -992,7 +1018,7 @@ public class Keyboard { private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { - if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mParams.mId)); + if (DEBUG) startTag("<%s> %s", TAG_SWITCH, mParams.mId); boolean selected = false; int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -1008,7 +1034,7 @@ public class Keyboard { } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); if (TAG_SWITCH.equals(tag)) { - if (DEBUG) Log.d(TAG, String.format("", TAG_SWITCH)); + if (DEBUG) endTag("", TAG_SWITCH); break; } else { throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); @@ -1057,10 +1083,8 @@ public class Keyboard { R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); final boolean hasShortcutKeyMatched = matchBoolean(a, R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); - // As noted at {@link KeyboardId} class, we are interested only in enum value - // masked by {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and - // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching - // this attribute with id.mImeOptions as integer value is enough for our purpose. + final boolean isMultiLineMatched = matchBoolean(a, + R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine()); final boolean imeActionMatched = matchInteger(a, R.styleable.Keyboard_Case_imeAction, id.imeAction()); final boolean localeCodeMatched = matchString(a, @@ -1072,30 +1096,42 @@ public class Keyboard { final boolean selected = keyboardSetElementMatched && modeMatched && navigateActionMatched && passwordInputMatched && hasSettingsKeyMatched && f2KeyModeMatched && clobberSettingsKeyMatched - && shortcutKeyEnabledMatched && hasShortcutKeyMatched && imeActionMatched - && localeCodeMatched && languageCodeMatched && countryCodeMatched; + && shortcutKeyEnabledMatched && hasShortcutKeyMatched && isMultiLineMatched + && imeActionMatched && localeCodeMatched && languageCodeMatched + && countryCodeMatched; - if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE, - textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), - "keyboardSetElement"), - textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), - booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"), - booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"), - booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"), - textAttr(KeyboardId.f2KeyModeName( - a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), "f2KeyMode"), - booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey, - "clobberSettingsKey"), - booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled, - "shortcutKeyEnabled"), - booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"), - textAttr(EditorInfoCompatUtils.imeOptionsName( - a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"), - textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), "localeCode"), - textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), - "languageCode"), - textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"), - Boolean.toString(selected))); + if (DEBUG) { + startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, + textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), + "keyboardSetElement"), + textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), + booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, + "navigateAction"), + booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, + "passwordInput"), + booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, + "hasSettingsKey"), + textAttr(KeyboardId.f2KeyModeName( + a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), + "f2KeyMode"), + booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey, + "clobberSettingsKey"), + booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled, + "shortcutKeyEnabled"), + booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, + "hasShortcutKey"), + booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine, + "isMultiLine"), + textAttr(a.getString(R.styleable.Keyboard_Case_imeAction), + "imeAction"), + textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), + "localeCode"), + textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), + "languageCode"), + textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), + "countryCode"), + selected ? "" : " skipped"); + } return selected; } finally { @@ -1148,7 +1184,7 @@ public class Keyboard { private boolean parseDefault(XmlPullParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { - if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT)); + if (DEBUG) startTag("<%s>", TAG_DEFAULT); if (row == null) { parseKeyboardContent(parser, skip); } else { @@ -1158,7 +1194,7 @@ public class Keyboard { } private void parseKeyStyle(XmlPullParser parser, boolean skip) - throws XmlPullParserException { + throws XmlPullParserException, IOException { TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_KeyStyle); TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), @@ -1167,12 +1203,18 @@ public class Keyboard { if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE + "/> needs styleName attribute", parser); + if (DEBUG) { + startEndTag("<%s styleName=%s />%s", TAG_KEY_STYLE, + keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName), + skip ? " skipped" : ""); + } if (!skip) mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); } finally { keyStyleAttr.recycle(); keyAttrs.recycle(); } + XmlParseUtils.checkEndTag(TAG_KEY_STYLE, parser); } private void startKeyboard() { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index edca87f5f..a000eae62 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -16,6 +16,7 @@ package com.android.inputmethod.keyboard; +import android.text.InputType; import android.text.TextUtils; import android.view.inputmethod.EditorInfo; @@ -25,10 +26,8 @@ import com.android.inputmethod.compat.InputTypeCompatUtils; import java.util.Arrays; import java.util.Locale; -// TODO: Move to com.android.inputmethod.keyboard.internal package. /** - * Represents the parameters necessary to construct a new LatinKeyboard, - * which also serve as a unique identifier for each keyboard type. + * Unique identifier for each keyboard type. */ public class KeyboardId { public static final int MODE_TEXT = 0; @@ -54,34 +53,37 @@ public class KeyboardId { private static final int F2KEY_MODE_SHORTCUT_IME = 2; private static final int F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS = 3; + private static final int IME_ACTION_CUSTOM_LABEL = EditorInfo.IME_MASK_ACTION + 1; + public final Locale mLocale; public final int mOrientation; public final int mWidth; public final int mMode; public final int mElementId; - private final int mInputType; - private final int mImeOptions; + private final EditorInfo mEditorInfo; private final boolean mSettingsKeyEnabled; public final boolean mClobberSettingsKey; public final boolean mShortcutKeyEnabled; public final boolean mHasShortcutKey; + public final String mCustomActionLabel; private final int mHashCode; public KeyboardId(int elementId, Locale locale, int orientation, int width, int mode, - int inputType, int imeOptions, boolean settingsKeyEnabled, boolean clobberSettingsKey, + EditorInfo editorInfo, boolean settingsKeyEnabled, boolean clobberSettingsKey, boolean shortcutKeyEnabled, boolean hasShortcutKey) { this.mLocale = locale; this.mOrientation = orientation; this.mWidth = width; this.mMode = mode; this.mElementId = elementId; - this.mInputType = inputType; - this.mImeOptions = imeOptions; + this.mEditorInfo = editorInfo; this.mSettingsKeyEnabled = settingsKeyEnabled; this.mClobberSettingsKey = clobberSettingsKey; this.mShortcutKeyEnabled = shortcutKeyEnabled; this.mHasShortcutKey = hasShortcutKey; + this.mCustomActionLabel = (editorInfo.actionLabel != null) + ? editorInfo.actionLabel.toString() : null; this.mHashCode = hashCode(this); } @@ -98,6 +100,7 @@ public class KeyboardId { id.mClobberSettingsKey, id.mShortcutKeyEnabled, id.mHasShortcutKey, + id.isMultiLine(), id.imeAction(), id.mLocale }); @@ -116,6 +119,7 @@ public class KeyboardId { && other.mClobberSettingsKey == this.mClobberSettingsKey && other.mShortcutKeyEnabled == this.mShortcutKeyEnabled && other.mHasShortcutKey == this.mHasShortcutKey + && other.isMultiLine() == this.isMultiLine() && other.imeAction() == this.imeAction() && other.mLocale.equals(this.mLocale); } @@ -151,22 +155,30 @@ public class KeyboardId { public boolean navigateAction() { // Note: Turn off checking navigation flag to show TAB key for now. - boolean navigateAction = InputTypeCompatUtils.isWebInputType(mInputType); + boolean navigateAction = InputTypeCompatUtils.isWebInputType(mEditorInfo.inputType); // || EditorInfoCompatUtils.hasFlagNavigateNext(mImeOptions) // || EditorInfoCompatUtils.hasFlagNavigatePrevious(mImeOptions); return navigateAction; } public boolean passwordInput() { - return InputTypeCompatUtils.isPasswordInputType(mInputType) - || InputTypeCompatUtils.isVisiblePasswordInputType(mInputType); + final int inputType = mEditorInfo.inputType; + return InputTypeCompatUtils.isPasswordInputType(inputType) + || InputTypeCompatUtils.isVisiblePasswordInputType(inputType); + } + + public boolean isMultiLine() { + return (mEditorInfo.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0; } public int imeAction() { - // We are interested only in {@link EditorInfo#IME_MASK_ACTION} enum value and - // {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION}. - return mImeOptions & ( - EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION); + if ((mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { + return EditorInfo.IME_ACTION_NONE; + } else if (mEditorInfo.actionLabel != null) { + return IME_ACTION_CUSTOM_LABEL; + } else { + return mEditorInfo.imeOptions & EditorInfo.IME_MASK_ACTION; + } } public boolean hasSettingsKey() { @@ -205,7 +217,7 @@ public class KeyboardId { mLocale, (mOrientation == 1 ? "port" : "land"), mWidth, modeName(mMode), - EditorInfoCompatUtils.imeOptionsName(imeAction()), + imeAction(), f2KeyModeName(f2KeyMode()), (mClobberSettingsKey ? " clobberSettingsKey" : ""), (navigateAction() ? " navigateAction" : ""), @@ -252,6 +264,11 @@ public class KeyboardId { } } + public static String actionName(int actionId) { + return (actionId == IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel" + : EditorInfoCompatUtils.imeActionName(actionId); + } + public static String f2KeyModeName(int f2KeyMode) { switch (f2KeyMode) { case F2KEY_MODE_NONE: return "none"; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index 82eaa1d17..f27170a89 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -62,6 +62,8 @@ public class KeyboardSet { new HashMap>(); private static final KeysCache sKeysCache = new KeysCache(); + private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo(); + public static class KeyboardSetException extends RuntimeException { public final KeyboardId mKeyboardId; public KeyboardSetException(Throwable cause, KeyboardId keyboardId) { @@ -94,8 +96,7 @@ public class KeyboardSet { static class Params { int mMode; - int mInputType; - int mImeOptions; + EditorInfo mEditorInfo; boolean mTouchPositionCorrectionEnabled; boolean mSettingsKeyEnabled; boolean mVoiceKeyEnabled; @@ -192,9 +193,8 @@ public class KeyboardSet { final boolean hasShortcutKey = params.mVoiceKeyEnabled && (isSymbols != params.mVoiceKeyOnMain); return new KeyboardId(keyboardSetElementId, params.mLocale, params.mOrientation, - params.mWidth, params.mMode, params.mInputType, params.mImeOptions, - params.mSettingsKeyEnabled, params.mNoSettingsKey, params.mVoiceKeyEnabled, - hasShortcutKey); + params.mWidth, params.mMode, params.mEditorInfo, params.mSettingsKeyEnabled, + params.mNoSettingsKey, params.mVoiceKeyEnabled, hasShortcutKey); } public static class Builder { @@ -213,10 +213,7 @@ public class KeyboardSet { final Params params = mParams; params.mMode = Utils.getKeyboardMode(editorInfo); - if (editorInfo != null) { - params.mInputType = editorInfo.inputType; - params.mImeOptions = editorInfo.imeOptions; - } + params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO; params.mNoSettingsKey = Utils.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo); } @@ -232,7 +229,8 @@ public class KeyboardSet { boolean touchPositionCorrectionEnabled) { final boolean deprecatedForceAscii = Utils.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); - final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(mParams.mImeOptions) + final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( + mParams.mEditorInfo.imeOptions) || deprecatedForceAscii; mParams.mLocale = (forceAscii && !asciiCapable) ? Locale.US : inputLocale; mParams.mTouchPositionCorrectionEnabled = touchPositionCorrectionEnabled; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 5b76b5449..8b8c0242d 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1224,6 +1224,41 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return mOptionsDialog != null && mOptionsDialog.isShowing(); } + private void insertPunctuationFromSuggestionStrip(final int code) { + onCodeInput(code, new int[] { code }, + KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, + KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); + } + + private static int getEditorActionId(EditorInfo editorInfo) { + if (editorInfo == null) return 0; + return (editorInfo.actionLabel != null) + ? editorInfo.actionId + : (editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION); + } + + private void performeEditorAction(int actionId) { + final InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + ic.performEditorAction(actionId); + } + } + + private void sendKeyCodePoint(int code) { + // TODO: Remove this special handling of digit letters. + // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. + if (code >= '0' && code <= '9') { + super.sendKeyChar((char)code); + return; + } + + final InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + final String text = new String(new int[] { code }, 0, 1); + ic.commitText(text, text.length()); + } + } + // Implementation of {@link KeyboardActionListener}. @Override public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { @@ -1264,6 +1299,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case Keyboard.CODE_SHORTCUT: mSubtypeSwitcher.switchToShortcutIME(); break; + case Keyboard.CODE_ACTION_ENTER: + performeEditorAction(getEditorActionId(getCurrentInputEditorInfo())); + break; case Keyboard.CODE_TAB: handleTab(); // There are two cases for tab. Either we send a "next" event, that may change the @@ -1301,7 +1339,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar commitTyped(ic); text = specificTldProcessingOnTextInput(ic, text); if (SPACE_STATE_PHANTOM == mSpaceState) { - sendKeyChar((char)Keyboard.CODE_SPACE); + sendKeyCodePoint(Keyboard.CODE_SPACE); } ic.commitText(text, 1); ic.endBatchEdit(); @@ -1448,10 +1486,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } + // TODO: Implement next and previous actions using other key code than tab's code. private void handleTab() { final int imeOptions = getCurrentInputEditorInfo().imeOptions; if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) { + // TODO: This should be {@link #sendKeyCodePoint(int)}. sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB); return; } @@ -1513,7 +1553,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Sanity check throw new RuntimeException("Should not be composing here"); } - sendKeyChar((char)Keyboard.CODE_SPACE); + sendKeyCodePoint(Keyboard.CODE_SPACE); } if ((isAlphabet(primaryCode) @@ -1549,7 +1589,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode, spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); - sendKeyChar((char)primaryCode); + sendKeyCodePoint(primaryCode); if (swapWeakSpace) { swapSwapperAndSpaceWhileInBatchEdit(ic); @@ -1595,11 +1635,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode, spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); - // TODO: rethink interactions of sendKeyChar, commitText("\n") and actions. sendKeyChar - // with a CODE_ENTER parameter will have the default InputMethodService implementation - // possibly redirect on the keyboard action. That may be the right thing to do, but - // on Shift+Enter, it's generally not, so we may want to do the redirection right here. - sendKeyChar((char)primaryCode); + sendKeyCodePoint(primaryCode); if (Keyboard.CODE_SPACE == primaryCode) { if (isSuggestionsRequested()) {