aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java58
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java22
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java168
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java56
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSet.java18
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java28
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java (renamed from java/src/com/android/inputmethod/keyboard/MiniKeyboard.java)53
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java (renamed from java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java)28
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java32
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java107
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java177
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java4
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java35
14 files changed, 451 insertions, 337 deletions
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 686392da8..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;
@@ -228,9 +229,9 @@ public class Key {
mDisabledIconId = style.getInt(keyAttr,
R.styleable.Keyboard_Key_keyIconDisabled, KeyboardIconsSet.ICON_UNDEFINED);
- mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags, 0);
+ mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags);
final boolean preserveCase = (mLabelFlags & LABEL_FLAGS_PRESERVE_CASE) != 0;
- int actionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags, 0);
+ int actionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
final String[] additionalMoreKeys = style.getStringArray(
keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys);
final String[] moreKeys = KeySpecParser.insertAddtionalMoreKeys(style.getStringArray(
@@ -245,10 +246,14 @@ public class Key {
mActionFlags = actionFlags;
mMoreKeys = moreKeys;
mMaxMoreKeysColumn = style.getInt(keyAttr,
- R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn);
+ R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn);
- mLabel = adjustCaseOfStringForKeyboardId(style.getString(
- keyAttr, R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId);
+ 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(
@@ -274,7 +279,12 @@ public class Key {
mCode = Keyboard.CODE_OUTPUT_TEXT;
}
} else if (code == Keyboard.CODE_UNSPECIFIED && outputText != null) {
- mCode = Keyboard.CODE_OUTPUT_TEXT;
+ if (Utils.codePointCount(outputText) == 1) {
+ mCode = outputText.codePointAt(0);
+ outputText = null;
+ } else {
+ mCode = Keyboard.CODE_OUTPUT_TEXT;
+ }
} else {
mCode = adjustCaseOfCodeForKeyboardId(code, preserveCase, params.mId);
}
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 10e0a5b01..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;
@@ -121,8 +121,8 @@ public class Keyboard {
/** More keys keyboard template */
public final int mMoreKeysTemplate;
- /** Maximum column for mini keyboard */
- public final int mMaxMiniKeyboardColumn;
+ /** Maximum column for more keys keyboard */
+ public final int mMaxMoreKeysKeyboardColumn;
/** List of keys and icons in this keyboard */
public final Set<Key> mKeys;
@@ -143,7 +143,7 @@ public class Keyboard {
mMostCommonKeyHeight = params.mMostCommonKeyHeight;
mMostCommonKeyWidth = params.mMostCommonKeyWidth;
mMoreKeysTemplate = params.mMoreKeysTemplate;
- mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn;
+ mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn;
mTopPadding = params.mTopPadding;
mVerticalGap = params.mVerticalGap;
@@ -226,7 +226,7 @@ public class Keyboard {
public int mVerticalGap;
public int mMoreKeysTemplate;
- public int mMaxMiniKeyboardColumn;
+ public int mMaxMoreKeysKeyboardColumn;
public int GRID_WIDTH;
public int GRID_HEIGHT;
@@ -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<KP extends Params> {
- 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) {
@@ -770,7 +791,7 @@ public class Keyboard {
params.mMoreKeysTemplate = keyboardAttr.getResourceId(
R.styleable.Keyboard_moreKeysTemplate, 0);
- params.mMaxMiniKeyboardColumn = keyAttr.getInt(
+ params.mMaxMoreKeysKeyboardColumn = keyAttr.getInt(
R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);
params.mIconsSet.loadIcons(keyboardAttr);
@@ -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("</%s>", 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("</%s>", 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("</%s>", tag);
if (TAG_ROW.equals(tag)) {
- if (DEBUG) Log.d(TAG, String.format("</%s>", 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("</%s>", 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("</%s> 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("</%s>", TAG_SWITCH));
+ if (DEBUG) endTag("</%s>", 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;
-
- 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)));
+ && shortcutKeyEnabledMatched && hasShortcutKeyMatched && isMultiLineMatched
+ && imeActionMatched && localeCodeMatched && languageCodeMatched
+ && countryCodeMatched;
+
+ 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 0837e17da..3ab24933c 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,7 +100,9 @@ public class KeyboardId {
id.mClobberSettingsKey,
id.mShortcutKeyEnabled,
id.mHasShortcutKey,
+ id.isMultiLine(),
id.imeAction(),
+ id.mCustomActionLabel,
id.mLocale
});
}
@@ -116,7 +120,9 @@ public class KeyboardId {
&& other.mClobberSettingsKey == this.mClobberSettingsKey
&& other.mShortcutKeyEnabled == this.mShortcutKeyEnabled
&& other.mHasShortcutKey == this.mHasShortcutKey
+ && other.isMultiLine() == this.isMultiLine()
&& other.imeAction() == this.imeAction()
+ && TextUtils.equals(other.mCustomActionLabel, this.mCustomActionLabel)
&& other.mLocale.equals(this.mLocale);
}
@@ -124,20 +130,17 @@ public class KeyboardId {
return mElementId < ELEMENT_SYMBOLS;
}
- // This should be aligned with {@link KeyboardShiftState#isShiftLocked}.
public boolean isAlphabetShiftLockedKeyboard() {
return mElementId == ELEMENT_ALPHABET_SHIFT_LOCKED
|| mElementId == ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED;
}
- // This should be aligned with {@link KeyboardShiftState#isShiftedOrShiftLocked}.
public boolean isAlphabetShiftedOrShiftLockedKeyboard() {
return isAlphabetKeyboard() && mElementId != ELEMENT_ALPHABET;
}
- // This should be aligned with {@link KeyboardShiftState#isManualShifted}.
public boolean isAlphabetManualShiftedKeyboard() {
- return mElementId != ELEMENT_ALPHABET_MANUAL_SHIFTED;
+ return mElementId == ELEMENT_ALPHABET_MANUAL_SHIFTED;
}
public boolean isSymbolsKeyboard() {
@@ -154,22 +157,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() {
@@ -208,7 +219,7 @@ public class KeyboardId {
mLocale,
(mOrientation == 1 ? "port" : "land"), mWidth,
modeName(mMode),
- EditorInfoCompatUtils.imeOptionsName(imeAction()),
+ imeAction(),
f2KeyModeName(f2KeyMode()),
(mClobberSettingsKey ? " clobberSettingsKey" : ""),
(navigateAction() ? " navigateAction" : ""),
@@ -255,6 +266,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<KeyboardId, SoftReference<Keyboard>>();
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/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 870c7cb25..88a41579d 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -92,13 +92,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private final Drawable mAutoCorrectionSpacebarLedIcon;
private static final int SPACE_LED_LENGTH_PERCENT = 80;
- // Mini keyboard
+ // More keys keyboard
private PopupWindow mMoreKeysWindow;
private MoreKeysPanel mMoreKeysPanel;
private int mMoreKeysPanelPointerTrackerId;
private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache =
new WeakHashMap<Key, MoreKeysPanel>();
- private final boolean mConfigShowMiniKeyboardAtTouchedPoint;
+ private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
private final PointerTrackerParams mPointerTrackerParams;
private final boolean mIsSpacebarTriggeringPopupByLongPress;
@@ -137,7 +137,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
break;
case MSG_LONGPRESS_KEY:
if (tracker != null) {
- keyboardView.openMiniKeyboardIfRequired(tracker.getKey(), tracker);
+ keyboardView.openMoreKeysKeyboardIfRequired(tracker.getKey(), tracker);
} else {
KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1);
}
@@ -338,8 +338,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
R.styleable.LatinKeyboardView_keyHysteresisDistance, 0);
mKeyDetector = new KeyDetector(keyHysteresisDistance);
mKeyTimerHandler = new KeyTimerHandler(this, keyTimerParams);
- mConfigShowMiniKeyboardAtTouchedPoint = a.getBoolean(
- R.styleable.LatinKeyboardView_showMiniKeyboardAtTouchedPoint, false);
+ mConfigShowMoreKeysKeyboardAtTouchedPoint = a.getBoolean(
+ R.styleable.LatinKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false);
a.recycle();
PointerTracker.setParameters(mPointerTrackerParams);
@@ -435,7 +435,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
super.cancelAllMessages();
}
- private boolean openMiniKeyboardIfRequired(Key parentKey, PointerTracker tracker) {
+ private boolean openMoreKeysKeyboardIfRequired(Key parentKey, PointerTracker tracker) {
// Check if we have a popup layout specified first.
if (mMoreKeysLayout == 0) {
return false;
@@ -458,19 +458,19 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
if (container == null)
throw new NullPointerException();
- final MiniKeyboardView miniKeyboardView =
- (MiniKeyboardView)container.findViewById(R.id.mini_keyboard_view);
+ final MoreKeysKeyboardView moreKeysKeyboardView =
+ (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view);
final Keyboard parentKeyboard = getKeyboard();
- final Keyboard miniKeyboard = new MiniKeyboard.Builder(
+ final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder(
this, parentKeyboard.mMoreKeysTemplate, parentKey, parentKeyboard).build();
- miniKeyboardView.setKeyboard(miniKeyboard);
+ moreKeysKeyboardView.setKeyboard(moreKeysKeyboard);
container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- return miniKeyboardView;
+ return moreKeysKeyboardView;
}
/**
- * Called when a key is long pressed. By default this will open mini keyboard associated
+ * Called when a key is long pressed. By default this will open more keys keyboard associated
* with this key.
* @param parentKey the key that was long pressed
* @param tracker the pointer tracker which pressed the parent key
@@ -524,13 +524,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
if (mMoreKeysWindow == null) {
mMoreKeysWindow = new PopupWindow(getContext());
mMoreKeysWindow.setBackgroundDrawable(null);
- mMoreKeysWindow.setAnimationStyle(R.style.MiniKeyboardAnimation);
+ mMoreKeysWindow.setAnimationStyle(R.style.MoreKeysKeyboardAnimation);
}
mMoreKeysPanel = moreKeysPanel;
mMoreKeysPanelPointerTrackerId = tracker.mPointerId;
final Keyboard keyboard = getKeyboard();
- final int pointX = (mConfigShowMiniKeyboardAtTouchedPoint) ? tracker.getLastX()
+ final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint) ? tracker.getLastX()
: parentKey.mX + parentKey.mWidth / 2;
final int pointY = parentKey.mY - keyboard.mVerticalGap;
moreKeysPanel.showMoreKeysPanel(
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index 4648da1c1..83155f719 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -21,10 +21,10 @@ import android.graphics.Paint;
import com.android.inputmethod.keyboard.internal.KeySpecParser;
import com.android.inputmethod.latin.R;
-public class MiniKeyboard extends Keyboard {
+public class MoreKeysKeyboard extends Keyboard {
private final int mDefaultKeyCoordX;
- private MiniKeyboard(Builder.MiniKeyboardParams params) {
+ private MoreKeysKeyboard(Builder.MoreKeysKeyboardParams params) {
super(params);
mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2;
}
@@ -33,21 +33,21 @@ public class MiniKeyboard extends Keyboard {
return mDefaultKeyCoordX;
}
- public static class Builder extends Keyboard.Builder<Builder.MiniKeyboardParams> {
+ public static class Builder extends Keyboard.Builder<Builder.MoreKeysKeyboardParams> {
private final String[] mMoreKeys;
- public static class MiniKeyboardParams extends Keyboard.Params {
+ public static class MoreKeysKeyboardParams extends Keyboard.Params {
/* package */int mTopRowAdjustment;
public int mNumRows;
public int mNumColumns;
public int mLeftKeys;
public int mRightKeys; // includes default key.
- public MiniKeyboardParams() {
+ public MoreKeysKeyboardParams() {
super();
}
- /* package for test */MiniKeyboardParams(int numKeys, int maxColumns, int keyWidth,
+ /* package for test */MoreKeysKeyboardParams(int numKeys, int maxColumns, int keyWidth,
int rowHeight, int coordXInParent, int parentKeyboardWidth) {
super();
setParameters(numKeys, maxColumns, keyWidth, rowHeight, coordXInParent,
@@ -55,21 +55,21 @@ public class MiniKeyboard extends Keyboard {
}
/**
- * Set keyboard parameters of mini keyboard.
+ * Set keyboard parameters of more keys keyboard.
*
- * @param numKeys number of keys in this mini keyboard.
- * @param maxColumns number of maximum columns of this mini keyboard.
- * @param keyWidth mini keyboard key width in pixel, including horizontal gap.
- * @param rowHeight mini keyboard row height in pixel, including vertical gap.
- * @param coordXInParent coordinate x of the popup key in parent keyboard.
+ * @param numKeys number of keys in this more keys keyboard.
+ * @param maxColumns number of maximum columns of this more keys keyboard.
+ * @param keyWidth more keys keyboard key width in pixel, including horizontal gap.
+ * @param rowHeight more keys keyboard row height in pixel, including vertical gap.
+ * @param coordXInParent coordinate x of the key preview in parent keyboard.
* @param parentKeyboardWidth parent keyboard width in pixel.
*/
public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight,
int coordXInParent, int parentKeyboardWidth) {
if (parentKeyboardWidth / keyWidth < maxColumns) {
throw new IllegalArgumentException(
- "Keyboard is too small to hold mini keyboard: " + parentKeyboardWidth
- + " " + keyWidth + " " + maxColumns);
+ "Keyboard is too small to hold more keys keyboard: "
+ + parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
}
mDefaultKeyWidth = keyWidth;
mDefaultRowHeight = rowHeight;
@@ -95,14 +95,14 @@ public class MiniKeyboard extends Keyboard {
leftKeys = numLeftKeys;
rightKeys = numRightKeys;
}
- // Shift right if the left edge of mini keyboard is on the edge of parent keyboard
- // unless the parent key is on the left edge.
+ // Shift right if the left edge of more keys keyboard is on the edge of parent
+ // keyboard unless the parent key is on the left edge.
if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) {
leftKeys--;
rightKeys++;
}
- // Shift left if the right edge of mini keyboard is on the edge of parent keyboard
- // unless the parent key is on the right edge.
+ // Shift left if the right edge of more keys keyboard is on the edge of parent
+ // keyboard unless the parent key is on the right edge.
if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) {
leftKeys++;
rightKeys--;
@@ -204,10 +204,10 @@ public class MiniKeyboard extends Keyboard {
}
public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) {
- super(view.getContext(), new MiniKeyboardParams());
+ super(view.getContext(), new MoreKeysKeyboardParams());
load(xmlId, parentKeyboard.mId);
- // TODO: Mini keyboard's vertical gap is currently calculated heuristically.
+ // TODO: More keys keyboard's vertical gap is currently calculated heuristically.
// Should revise the algorithm.
mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2;
mMoreKeys = parentKey.mMoreKeys;
@@ -215,8 +215,9 @@ public class MiniKeyboard extends Keyboard {
final int previewWidth = view.mKeyPreviewDrawParams.mPreviewBackgroundWidth;
final int previewHeight = view.mKeyPreviewDrawParams.mPreviewBackgroundHeight;
final int width, height;
- // Use pre-computed width and height if these values are available and mini keyboard
- // has only one key to mitigate visual flicker between key preview and mini keyboard.
+ // Use pre-computed width and height if these values are available and more keys
+ // keyboard has only one key to mitigate visual flicker between key preview and more
+ // keys keyboard.
if (view.isKeyPreviewPopupEnabled() && mMoreKeys.length == 1 && previewWidth > 0
&& previewHeight > 0) {
width = previewWidth;
@@ -231,7 +232,7 @@ public class MiniKeyboard extends Keyboard {
private static int getMaxKeyWidth(KeyboardView view, String[] moreKeys, int minKeyWidth) {
final int padding = (int) view.getContext().getResources()
- .getDimension(R.dimen.mini_keyboard_key_horizontal_padding);
+ .getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding);
Paint paint = null;
int maxWidth = minKeyWidth;
for (String moreKeySpec : moreKeys) {
@@ -252,8 +253,8 @@ public class MiniKeyboard extends Keyboard {
}
@Override
- public MiniKeyboard build() {
- final MiniKeyboardParams params = mParams;
+ public MoreKeysKeyboard build() {
+ final MoreKeysKeyboardParams params = mParams;
for (int n = 0; n < mMoreKeys.length; n++) {
final String moreKeySpec = mMoreKeys[n];
final int row = n / params.mNumColumns;
@@ -262,7 +263,7 @@ public class MiniKeyboard extends Keyboard {
params.markAsEdgeKey(key, row);
params.onAddKey(key);
}
- return new MiniKeyboard(params);
+ return new MoreKeysKeyboard(params);
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index 72d5b6889..b030dd95a 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -28,10 +28,10 @@ import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.latin.R;
/**
- * A view that renders a virtual {@link MiniKeyboard}. It handles rendering of keys and detecting
- * key presses and touch movements.
+ * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and
+ * detecting key presses and touch movements.
*/
-public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
+public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
private final int[] mCoordinates = new int[2];
private final KeyDetector mKeyDetector;
@@ -43,7 +43,7 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter();
- private final KeyboardActionListener mMiniKeyboardListener =
+ private final KeyboardActionListener mMoreKeysKeyboardListener =
new KeyboardActionListener.Adapter() {
@Override
public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
@@ -71,16 +71,16 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
}
};
- public MiniKeyboardView(Context context, AttributeSet attrs) {
- this(context, attrs, R.attr.miniKeyboardViewStyle);
+ public MoreKeysKeyboardView(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.moreKeysKeyboardViewStyle);
}
- public MiniKeyboardView(Context context, AttributeSet attrs, int defStyle) {
+ public MoreKeysKeyboardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final Resources res = context.getResources();
mKeyDetector = new MoreKeysDetector(
- res.getDimension(R.dimen.mini_keyboard_slide_allowance));
+ res.getDimension(R.dimen.more_keys_keyboard_slide_allowance));
setKeyPreviewPopupEnabled(false, 0);
}
@@ -110,7 +110,7 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
@Override
public KeyboardActionListener getKeyboardActionListener() {
- return mMiniKeyboardListener;
+ return mMoreKeysKeyboardListener;
}
@Override
@@ -125,7 +125,7 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
@Override
public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) {
- // Mini keyboard needs no pop-up key preview displayed, so we pass always false with a
+ // More keys keyboard needs no pop-up key preview displayed, so we pass always false with a
// delay of 0. The delay does not matter actually since the popup is not shown anyway.
super.setKeyPreviewPopupEnabled(false, 0);
}
@@ -136,13 +136,13 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
mController = controller;
mListener = listener;
final View container = (View)getParent();
- final MiniKeyboard miniKeyboard = (MiniKeyboard)getKeyboard();
+ final MoreKeysKeyboard moreKeysKeyboard = (MoreKeysKeyboard)getKeyboard();
parentView.getLocationInWindow(mCoordinates);
- final int miniKeyboardLeft = pointX - miniKeyboard.getDefaultCoordX()
+ final int moreKeysKeyboardLeft = pointX - moreKeysKeyboard.getDefaultCoordX()
+ parentView.getPaddingLeft();
- final int x = wrapUp(Math.max(0, Math.min(miniKeyboardLeft,
- parentView.getWidth() - miniKeyboard.mOccupiedWidth))
+ final int x = wrapUp(Math.max(0, Math.min(moreKeysKeyboardLeft,
+ parentView.getWidth() - moreKeysKeyboard.mOccupiedWidth))
- container.getPaddingLeft() + mCoordinates[0],
container.getMeasuredWidth(), 0, parentView.getWidth());
final int y = pointY
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 2d1a0083d..41e7ef435 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -59,7 +59,7 @@ public class ProximityInfo {
mKeyHeight = keyHeight;
mGridNeighbors = new Key[mGridSize][];
if (minWidth == 0 || height == 0) {
- // No proximity required. Keyboard might be mini keyboard.
+ // No proximity required. Keyboard might be more keys keyboard.
return;
}
computeNearestNeighbors(keyWidth, keys, touchPositionCorrection, additionalProximityChars);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index e3c5da456..1626a140b 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -133,18 +133,28 @@ public class KeySpecParser {
return label;
}
+ private static String getOutputTextInternal(String moreKeySpec) {
+ final int end = indexOfLabelEnd(moreKeySpec, 0);
+ if (end <= 0) {
+ return null;
+ }
+ if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
+ throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec);
+ }
+ return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1));
+ }
+
public static String getOutputText(String moreKeySpec) {
if (hasCode(moreKeySpec)) {
return null;
}
- final int end = indexOfLabelEnd(moreKeySpec, 0);
- if (end > 0) {
- if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
- throw new KeySpecParserError("Multiple " + LABEL_END + ": "
- + moreKeySpec);
+ final String outputText = getOutputTextInternal(moreKeySpec);
+ if (outputText != null) {
+ if (Utils.codePointCount(outputText) == 1) {
+ // If output text is one code point, it should be treated as a code.
+ // See {@link #getCode(Resources, String)}.
+ return null;
}
- final String outputText = parseEscape(
- moreKeySpec.substring(end + /* LABEL_END */1));
if (!TextUtils.isEmpty(outputText)) {
return outputText;
}
@@ -170,7 +180,13 @@ public class KeySpecParser {
final int code = res.getInteger(resId);
return code;
}
- if (indexOfLabelEnd(moreKeySpec, 0) > 0) {
+ final String outputText = getOutputTextInternal(moreKeySpec);
+ if (outputText != null) {
+ // If output text is one code point, it should be treated as a code.
+ // See {@link #getOutputText(String)}.
+ if (Utils.codePointCount(outputText) == 1) {
+ return outputText.codePointAt(0);
+ }
return Keyboard.CODE_OUTPUT_TEXT;
}
final String label = getLabel(moreKeySpec);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
index 6ec56ca9f..12a9c51f2 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
@@ -40,17 +40,13 @@ public class KeyStyles {
public String[] getStringArray(TypedArray a, int index);
public String getString(TypedArray a, int index);
public int getInt(TypedArray a, int index, int defaultValue);
- public int getFlag(TypedArray a, int index, int defaultValue);
+ public int getFlag(TypedArray a, int index);
}
- private static class EmptyKeyStyle implements KeyStyle {
- EmptyKeyStyle() {
- // Nothing to do.
- }
-
+ static class EmptyKeyStyle implements KeyStyle {
@Override
public String[] getStringArray(TypedArray a, int index) {
- return parseStringArray(a, index);
+ return KeyStyles.parseStringArray(a, index);
}
@Override
@@ -64,50 +60,47 @@ public class KeyStyles {
}
@Override
- public int getFlag(TypedArray a, int index, int defaultValue) {
- return a.getInt(index, defaultValue);
- }
-
- protected static String[] parseStringArray(TypedArray a, int index) {
- if (!a.hasValue(index))
- return null;
- return KeySpecParser.parseCsvString(
- a.getString(index), a.getResources(), R.string.english_ime_name);
+ public int getFlag(TypedArray a, int index) {
+ return a.getInt(index, 0);
}
}
- private static class DeclaredKeyStyle extends EmptyKeyStyle {
- private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>();
+ static class DeclaredKeyStyle implements KeyStyle {
+ private final HashMap<Integer, Object> mStyleAttributes = new HashMap<Integer, Object>();
@Override
public String[] getStringArray(TypedArray a, int index) {
- return a.hasValue(index)
- ? super.getStringArray(a, index) : (String[])mAttributes.get(index);
+ if (a.hasValue(index)) {
+ return parseStringArray(a, index);
+ }
+ return (String[])mStyleAttributes.get(index);
}
@Override
public String getString(TypedArray a, int index) {
- return a.hasValue(index)
- ? super.getString(a, index) : (String)mAttributes.get(index);
+ if (a.hasValue(index)) {
+ return a.getString(index);
+ }
+ return (String)mStyleAttributes.get(index);
}
@Override
public int getInt(TypedArray a, int index, int defaultValue) {
- final Integer value = (Integer)mAttributes.get(index);
- return super.getInt(a, index, (value != null) ? value : defaultValue);
+ if (a.hasValue(index)) {
+ return a.getInt(index, defaultValue);
+ }
+ final Integer styleValue = (Integer)mStyleAttributes.get(index);
+ return styleValue != null ? styleValue : defaultValue;
}
@Override
- public int getFlag(TypedArray a, int index, int defaultValue) {
- final Integer value = (Integer)mAttributes.get(index);
- return super.getFlag(a, index, defaultValue) | (value != null ? value : 0);
- }
-
- DeclaredKeyStyle() {
- super();
+ public int getFlag(TypedArray a, int index) {
+ final int value = a.getInt(index, 0);
+ final Integer styleValue = (Integer)mStyleAttributes.get(index);
+ return (styleValue != null ? styleValue : 0) | value;
}
- void parseKeyStyleAttributes(TypedArray keyAttr) {
+ void readKeyAttributes(TypedArray keyAttr) {
// TODO: Currently not all Key attributes can be declared as style.
readInt(keyAttr, R.styleable.Keyboard_Key_code);
readInt(keyAttr, R.styleable.Keyboard_Key_altCode);
@@ -126,52 +119,68 @@ public class KeyStyles {
}
private void readString(TypedArray a, int index) {
- if (a.hasValue(index))
- mAttributes.put(index, a.getString(index));
+ if (a.hasValue(index)) {
+ mStyleAttributes.put(index, a.getString(index));
+ }
}
private void readInt(TypedArray a, int index) {
- if (a.hasValue(index))
- mAttributes.put(index, a.getInt(index, 0));
+ if (a.hasValue(index)) {
+ mStyleAttributes.put(index, a.getInt(index, 0));
+ }
}
private void readFlag(TypedArray a, int index) {
- final Integer value = (Integer)mAttributes.get(index);
- if (a.hasValue(index))
- mAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
+ final Integer value = (Integer)mStyleAttributes.get(index);
+ if (a.hasValue(index)) {
+ mStyleAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
+ }
}
private void readStringArray(TypedArray a, int index) {
final String[] value = parseStringArray(a, index);
- if (value != null)
- mAttributes.put(index, value);
+ if (value != null) {
+ mStyleAttributes.put(index, value);
+ }
+ }
+
+ void addParentStyleAttributes(DeclaredKeyStyle parentStyle) {
+ mStyleAttributes.putAll(parentStyle.mStyleAttributes);
}
+ }
- void addParent(DeclaredKeyStyle parentStyle) {
- mAttributes.putAll(parentStyle.mAttributes);
+ static String[] parseStringArray(TypedArray a, int index) {
+ if (a.hasValue(index)) {
+ return KeySpecParser.parseCsvString(
+ a.getString(index), a.getResources(), R.string.english_ime_name);
}
+ return null;
}
public void parseKeyStyleAttributes(TypedArray keyStyleAttr, TypedArray keyAttrs,
XmlPullParser parser) throws XmlPullParserException {
final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName);
- if (DEBUG) Log.d(TAG, String.format("<%s styleName=%s />",
- Keyboard.Builder.TAG_KEY_STYLE, styleName));
- if (mStyles.containsKey(styleName))
+ if (DEBUG) {
+ Log.d(TAG, String.format("<%s styleName=%s />",
+ Keyboard.Builder.TAG_KEY_STYLE, styleName));
+ }
+ if (mStyles.containsKey(styleName)) {
throw new XmlParseUtils.ParseException(
"duplicate key style declared: " + styleName, parser);
+ }
final DeclaredKeyStyle style = new DeclaredKeyStyle();
if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
final String parentStyle = keyStyleAttr.getString(
R.styleable.Keyboard_KeyStyle_parentStyle);
final DeclaredKeyStyle parent = mStyles.get(parentStyle);
- if (parent == null)
+ if (parent == null) {
throw new XmlParseUtils.ParseException(
"Unknown parentStyle " + parentStyle, parser);
- style.addParent(parent);
+ }
+ style.addParentStyleAttributes(parent);
}
- style.parseKeyStyleAttributes(keyAttrs);
+ style.readKeyAttributes(keyAttrs);
mStyles.put(styleName, style);
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 8aaa0692f..1cb79e707 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -187,7 +187,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private View mKeyPreviewBackingView;
private View mSuggestionsContainer;
private SuggestionsView mSuggestionsView;
- private Suggest mSuggest;
+ /* package for tests */ Suggest mSuggest;
private CompletionInfo[] mApplicationSpecifiedCompletions;
private InputMethodManagerCompatWrapper mImm;
@@ -1225,12 +1225,41 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
return mOptionsDialog != null && mOptionsDialog.isShowing();
}
- private void insertPunctuationFromSuggestionStrip(final InputConnection ic, final int code) {
+ 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) {
@@ -1271,6 +1300,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
@@ -1308,7 +1340,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();
@@ -1327,10 +1359,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// Not a tld: do nothing.
return text;
}
+ // We have a TLD (or something that looks like this): make sure we don't add
+ // a space even if currently in phantom mode.
+ mSpaceState = SPACE_STATE_NONE;
final CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
if (lastOne != null && lastOne.length() == 1
&& lastOne.charAt(0) == Keyboard.CODE_PERIOD) {
- mSpaceState = SPACE_STATE_NONE;
return text.subSequence(1, text.length());
} else {
return text;
@@ -1399,7 +1433,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
if (SPACE_STATE_DOUBLE == spaceState) {
- if (revertDoubleSpace(ic)) {
+ if (revertDoubleSpaceWhileInBatchEdit(ic)) {
// No need to reset mSpaceState, it has already be done (that's why we
// receive it as a parameter)
return;
@@ -1453,10 +1487,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;
}
@@ -1475,6 +1511,28 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
+ // ic may be null
+ private boolean maybeStripSpaceWhileInBatchEdit(final InputConnection ic, final int code,
+ final int spaceState, final boolean isFromSuggestionStrip) {
+ if (Keyboard.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
+ removeTrailingSpaceWhileInBatchEdit(ic);
+ return false;
+ } else if ((SPACE_STATE_WEAK == spaceState
+ || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
+ && isFromSuggestionStrip) {
+ if (mSettingsValues.isMagicSpaceSwapper(code)) {
+ return true;
+ } else {
+ if (mSettingsValues.isMagicSpaceStripper(code)) {
+ removeTrailingSpaceWhileInBatchEdit(ic);
+ }
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
private void handleCharacter(final int primaryCode, final int[] keyCodes, final int x,
final int y, final int spaceState) {
mVoiceProxy.handleCharacter();
@@ -1489,7 +1547,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private void handleCharacterWhileInBatchEdit(final int primaryCode, final int[] keyCodes,
final int x, final int y, final int spaceState, final InputConnection ic) {
boolean isComposingWord = mWordComposer.isComposingWord();
- int code = primaryCode;
if (SPACE_STATE_PHANTOM == spaceState &&
!mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode)) {
@@ -1497,17 +1554,18 @@ 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(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code))
+ if ((isAlphabet(primaryCode)
+ || mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode))
&& isSuggestionsRequested() && !isCursorTouchingWord()) {
if (!isComposingWord) {
// Reset entirely the composing state anyway, then start composing a new word unless
// the character is a single quote. The idea here is, single quote is not a
// separator and it should be treated as a normal character, except in the first
// position where it should not start composing a word.
- isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != code);
+ isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode);
// Here we don't need to reset the last composed word. It will be reset
// when we commit this one, if we ever do; if on the other hand we backspace
// it entirely and resume suggestions on the previous word, we'd like to still
@@ -1518,7 +1576,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
if (isComposingWord) {
- mWordComposer.add(code, keyCodes, x, y);
+ mWordComposer.add(primaryCode, keyCodes, x, y);
if (ic != null) {
// If it's the first letter, make note of auto-caps state
if (mWordComposer.size() == 1) {
@@ -1529,14 +1587,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
mHandler.postUpdateSuggestions();
} else {
- sendKeyChar((char)code);
- }
+ final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode,
+ spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x);
- if (mSettingsValues.isWordSeparator(code)) {
- Utils.Stats.onSeparator((char)code, x, y);
- } else {
- Utils.Stats.onNonSeparator((char)code, x, y);
+ sendKeyCodePoint(primaryCode);
+
+ if (swapWeakSpace) {
+ swapSwapperAndSpaceWhileInBatchEdit(ic);
+ mSpaceState = SPACE_STATE_WEAK;
+ }
}
+ Utils.Stats.onNonSeparator((char)primaryCode, x, y);
}
// Returns true if we did an autocorrection, false otherwise.
@@ -1572,29 +1633,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
- final boolean swapWeakSpace;
- if (Keyboard.CODE_ENTER == primaryCode && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
- removeTrailingSpaceWhileInBatchEdit(ic);
- swapWeakSpace = false;
- } else if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
- && KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x) {
- if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
- swapWeakSpace = true;
- } else {
- swapWeakSpace = false;
- if (mSettingsValues.isMagicSpaceStripper(primaryCode)) {
- removeTrailingSpaceWhileInBatchEdit(ic);
- }
- }
- } else {
- swapWeakSpace = false;
- }
+ 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()) {
@@ -1613,7 +1655,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
} else {
if (swapWeakSpace) {
swapSwapperAndSpaceWhileInBatchEdit(ic);
- mSpaceState = SPACE_STATE_WEAK;
+ mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
} else if (SPACE_STATE_PHANTOM == spaceState) {
// If we are in phantom space state, and the user presses a separator, we want to
// stay in phantom space state so that the next keypress has a chance to add the
@@ -1869,52 +1911,40 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
@Override
- public void pickSuggestionManually(int index, CharSequence suggestion) {
+ public void pickSuggestionManually(final int index, final CharSequence suggestion) {
mComposingStateManager.onFinishComposingText();
- SuggestedWords suggestions = mSuggestionsView.getSuggestions();
+ final SuggestedWords suggestions = mSuggestionsView.getSuggestions();
mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion,
mSettingsValues.mWordSeparators);
- final InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.beginBatchEdit();
- }
if (mInputAttributes.mApplicationSpecifiedCompletionOn
&& mApplicationSpecifiedCompletions != null
&& index >= 0 && index < mApplicationSpecifiedCompletions.length) {
- if (ic != null) {
- final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
- ic.commitCompletion(completionInfo);
- }
if (mSuggestionsView != null) {
mSuggestionsView.clear();
}
mKeyboardSwitcher.updateShiftState();
+ final InputConnection ic = getCurrentInputConnection();
if (ic != null) {
+ ic.beginBatchEdit();
+ final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
+ ic.commitCompletion(completionInfo);
ic.endBatchEdit();
}
return;
}
- // If this is a punctuation, apply it through the normal key press
- if (suggestion.length() == 1 && (mSettingsValues.isWordSeparator(suggestion.charAt(0))
- || mSettingsValues.isSuggestedPunctuation(suggestion.charAt(0)))) {
+ // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput
+ if (suggestion.length() == 1 && isShowingPunctuationList()) {
// Word separators are suggested before the user inputs something.
// So, LatinImeLogger logs "" as a user's input.
LatinImeLogger.logOnManualSuggestion(
"", suggestion.toString(), index, suggestions.mWords);
- final CharSequence outputText = mSettingsValues.mSuggestPuncOutputTextList
- .getWord(index);
- final int primaryCode = outputText.charAt(0);
- // Find out whether the previous character is a space. If it is, as a special case
- // for punctuation entered through the suggestion strip, it should be swapped
- // if it was a magic or a weak space. This is meant to help in case the user
- // pressed space on purpose of displaying the suggestion strip punctuation.
- insertPunctuationFromSuggestionStrip(ic, primaryCode);
- // TODO: the following endBatchEdit seems useless, check
- if (ic != null) {
- ic.endBatchEdit();
- }
+ // Rely on onCodeInput to do the complicated swapping/stripping logic consistently.
+ final int primaryCode = suggestion.charAt(0);
+ onCodeInput(primaryCode, new int[] { primaryCode },
+ KeyboardActionListener.SUGGESTION_STRIP_COORDINATE,
+ KeyboardActionListener.SUGGESTION_STRIP_COORDINATE);
return;
}
// We need to log before we commit, because the word composer will store away the user
@@ -1967,9 +1997,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mHandler.postUpdateSuggestions();
}
}
- if (ic != null) {
- ic.endBatchEdit();
- }
}
/**
@@ -2081,21 +2108,20 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
CharSequence toRight = ic.getTextAfterCursor(1, 0);
if (!TextUtils.isEmpty(toLeft)
- && !mSettingsValues.isWordSeparator(toLeft.charAt(0))
- && !mSettingsValues.isSuggestedPunctuation(toLeft.charAt(0))) {
+ && !mSettingsValues.isWordSeparator(toLeft.charAt(0))) {
return true;
}
if (!TextUtils.isEmpty(toRight)
- && !mSettingsValues.isWordSeparator(toRight.charAt(0))
- && !mSettingsValues.isSuggestedPunctuation(toRight.charAt(0))) {
+ && !mSettingsValues.isWordSeparator(toRight.charAt(0))) {
return true;
}
return false;
}
// "ic" must not be null
- private static boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) {
- CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
+ private static boolean sameAsTextBeforeCursor(final InputConnection ic,
+ final CharSequence text) {
+ final CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
return TextUtils.equals(text, beforeText);
}
@@ -2212,13 +2238,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
ic.deleteSurroundingText(restartLength, 0);
+ mComposingStateManager.onStartComposingText();
ic.setComposingText(mWordComposer.getTypedWord(), 1);
mHandler.cancelUpdateBigramPredictions();
mHandler.postUpdateSuggestions();
}
// "ic" must not be null
- private boolean revertDoubleSpace(final InputConnection ic) {
+ private boolean revertDoubleSpaceWhileInBatchEdit(final InputConnection ic) {
mHandler.cancelDoubleSpacesTimer();
// Here we test whether we indeed have a period and a space before us. This should not
// be needed, but it's there just in case something went wrong.
@@ -2231,10 +2258,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
+ "\". \" just before the cursor.");
return false;
}
- ic.beginBatchEdit();
ic.deleteSurroundingText(2, 0);
ic.commitText(" ", 1);
- ic.endBatchEdit();
return true;
}
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 589cb6f86..6b652313c 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -222,10 +222,6 @@ public class SettingsValues {
res.getBoolean(R.bool.config_default_vibration_enabled));
}
- public boolean isSuggestedPunctuation(int code) {
- return mSuggestPuncs.contains(String.valueOf((char)code));
- }
-
public boolean isWordSeparator(int code) {
return mWordSeparators.contains(String.valueOf((char)code));
}
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index f418968b5..a1a329a8d 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -90,11 +90,11 @@ public class WordComposer {
* @return the number of keystrokes
*/
public final int size() {
- return mTypedWord.length();
+ return mCodes.size();
}
public final boolean isComposingWord() {
- return size() > 0;
+ return mCodes.size() > 0;
}
/**
@@ -125,8 +125,8 @@ public class WordComposer {
* @param codes the array of unicode values
*/
public void add(int primaryCode, int[] codes, int x, int y) {
- final int newIndex = size();
- mTypedWord.append((char) primaryCode);
+ final int newIndex = mCodes.size();
+ mTypedWord.appendCodePoint(primaryCode);
correctPrimaryJuxtapos(primaryCode, codes);
mCodes.add(codes);
if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) {
@@ -171,8 +171,8 @@ public class WordComposer {
final KeyDetector keyDetector) {
reset();
final int length = word.length();
- for (int i = 0; i < length; ++i) {
- int codePoint = word.charAt(i);
+ for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) {
+ int codePoint = Character.codePointAt(word, i);
addKeyInfo(codePoint, keyboard, keyDetector);
}
}
@@ -207,16 +207,25 @@ public class WordComposer {
* Delete the last keystroke as a result of hitting backspace.
*/
public void deleteLast() {
- final int size = size();
+ final int size = mCodes.size();
if (size > 0) {
- final int lastPos = size - 1;
- char lastChar = mTypedWord.charAt(lastPos);
- mCodes.remove(lastPos);
- // TODO: This crashes and catches fire if the code point doesn't fit a char
- mTypedWord.deleteCharAt(lastPos);
+ mCodes.remove(size - 1);
+ // Note: mTypedWord.length() and mCodes.length differ when there are surrogate pairs
+ final int stringBuilderLength = mTypedWord.length();
+ if (stringBuilderLength < size) {
+ throw new RuntimeException(
+ "In WordComposer: mCodes and mTypedWords have non-matching lengths");
+ }
+ final int lastChar = mTypedWord.codePointBefore(stringBuilderLength);
+ if (Character.isSupplementaryCodePoint(lastChar)) {
+ mTypedWord.delete(stringBuilderLength - 2, stringBuilderLength);
+ } else {
+ mTypedWord.deleteCharAt(stringBuilderLength - 1);
+ }
if (Character.isUpperCase(lastChar)) mCapsCount--;
}
- if (size() == 0) {
+ // We may have deleted the last one.
+ if (0 == mCodes.size()) {
mIsFirstCharCapitalized = false;
}
if (mTrailingSingleQuotesCount > 0) {