aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java191
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java1166
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java67
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java252
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java9
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java427
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java16
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java11
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java163
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java106
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java92
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java46
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java (renamed from java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java)80
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java826
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java143
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java154
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeysCache.java40
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java61
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java76
-rw-r--r--java/src/com/android/inputmethod/latin/ResourceUtils.java80
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java238
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java272
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java19
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java2
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java2
25 files changed, 2483 insertions, 2056 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 178c9ff05..e941cc7fc 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -32,10 +32,13 @@ import android.util.Log;
import android.util.Xml;
import com.android.inputmethod.keyboard.internal.KeySpecParser;
-import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
-import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle;
+import com.android.inputmethod.keyboard.internal.KeyStyle;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.keyboard.internal.KeyboardParams;
+import com.android.inputmethod.keyboard.internal.KeyboardRow;
+import com.android.inputmethod.keyboard.internal.MoreKeySpec;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResourceUtils;
import com.android.inputmethod.latin.StringUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -54,7 +57,6 @@ public class Key {
* The key code (unicode or custom code) that this key generates.
*/
public final int mCode;
- public final int mAltCode;
/** Label to display */
public final String mLabel;
@@ -89,22 +91,11 @@ public class Key {
/** Icon to display instead of a label. Icon takes precedence over a label */
private final int mIconId;
- /** Icon for disabled state */
- private final int mDisabledIconId;
- /** Preview version of the icon, for the preview popup */
- private final int mPreviewIconId;
/** Width of the key, not including the gap */
public final int mWidth;
/** Height of the key, not including the gap */
public final int mHeight;
- /** The horizontal gap around this key */
- public final int mHorizontalGap;
- /** The vertical gap below this key */
- public final int mVerticalGap;
- /** The visual insets */
- public final int mVisualInsetsLeft;
- public final int mVisualInsetsRight;
/** X coordinate of the key in the keyboard layout */
public final int mX;
/** Y coordinate of the key in the keyboard layout */
@@ -112,8 +103,6 @@ public class Key {
/** Hit bounding box of the key */
public final Rect mHitBox = new Rect();
- /** Text to output when pressed. This can be multiple characters, like ".com" */
- public final CharSequence mOutputText;
/** More keys */
public final MoreKeySpec[] mMoreKeys;
/** More keys column number and flags */
@@ -143,6 +132,32 @@ public class Key {
private static final int ACTION_FLAGS_ALT_CODE_WHILE_TYPING = 0x04;
private static final int ACTION_FLAGS_ENABLE_LONG_PRESS = 0x08;
+ private final OptionalAttributes mOptionalAttributes;
+
+ private static class OptionalAttributes {
+ /** Text to output when pressed. This can be multiple characters, like ".com" */
+ public final String mOutputText;
+ public final int mAltCode;
+ /** Icon for disabled state */
+ public final int mDisabledIconId;
+ /** Preview version of the icon, for the preview popup */
+ public final int mPreviewIconId;
+ /** The visual insets */
+ public final int mVisualInsetsLeft;
+ public final int mVisualInsetsRight;
+
+ public OptionalAttributes(final String outputText, final int altCode,
+ final int disabledIconId, final int previewIconId,
+ final int visualInsetsLeft, final int visualInsetsRight) {
+ mOutputText = outputText;
+ mAltCode = altCode;
+ mDisabledIconId = disabledIconId;
+ mPreviewIconId = previewIconId;
+ mVisualInsetsLeft = visualInsetsLeft;
+ mVisualInsetsRight = visualInsetsRight;
+ }
+ }
+
private final int mHashCode;
/** The current pressed state of this key */
@@ -153,8 +168,8 @@ public class Key {
/**
* This constructor is being used only for keys in more keys keyboard.
*/
- public Key(Keyboard.Params params, MoreKeySpec moreKeySpec, int x, int y, int width, int height,
- int labelFlags) {
+ public Key(final KeyboardParams params, final MoreKeySpec moreKeySpec, final int x, final int y,
+ final int width, final int height, final int labelFlags) {
this(params, moreKeySpec.mLabel, null, moreKeySpec.mIconId, moreKeySpec.mCode,
moreKeySpec.mOutputText, x, y, width, height, labelFlags);
}
@@ -162,13 +177,11 @@ public class Key {
/**
* This constructor is being used only for key in popup suggestions pane.
*/
- public Key(Keyboard.Params params, String label, String hintLabel, int iconId,
- int code, String outputText, int x, int y, int width, int height, int labelFlags) {
+ public Key(final KeyboardParams params, final String label, final String hintLabel,
+ final int iconId, final int code, final String outputText, final int x, final int y,
+ final int width, final int height, final int labelFlags) {
mHeight = height - params.mVerticalGap;
- mHorizontalGap = params.mHorizontalGap;
- mVerticalGap = params.mVerticalGap;
- mVisualInsetsLeft = mVisualInsetsRight = 0;
- mWidth = width - mHorizontalGap;
+ mWidth = width - params.mHorizontalGap;
mHintLabel = hintLabel;
mLabelFlags = labelFlags;
mBackgroundType = BACKGROUND_TYPE_NORMAL;
@@ -176,15 +189,17 @@ public class Key {
mMoreKeys = null;
mMoreKeysColumnAndFlags = 0;
mLabel = label;
- mOutputText = outputText;
+ if (outputText == null) {
+ mOptionalAttributes = null;
+ } else {
+ mOptionalAttributes = new OptionalAttributes(outputText, CODE_UNSPECIFIED,
+ ICON_UNDEFINED, ICON_UNDEFINED, 0, 0);
+ }
mCode = code;
mEnabled = (code != CODE_UNSPECIFIED);
- mAltCode = CODE_UNSPECIFIED;
mIconId = iconId;
- mDisabledIconId = ICON_UNDEFINED;
- mPreviewIconId = ICON_UNDEFINED;
// Horizontal gap is divided equally to both sides of the key.
- mX = x + mHorizontalGap / 2;
+ mX = x + params.mHorizontalGap / 2;
mY = y;
mHitBox.set(x, y, x + width + 1, y + height);
@@ -201,12 +216,11 @@ public class Key {
* @param parser the XML parser containing the attributes for this key
* @throws XmlPullParserException
*/
- public Key(Resources res, Keyboard.Params params, Keyboard.Builder.Row row,
- XmlPullParser parser) throws XmlPullParserException {
+ public Key(final Resources res, final KeyboardParams params, final KeyboardRow row,
+ final XmlPullParser parser) throws XmlPullParserException {
final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
final int keyHeight = row.mRowHeight;
- mVerticalGap = params.mVerticalGap;
- mHeight = keyHeight - mVerticalGap;
+ mHeight = keyHeight - params.mVerticalGap;
final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard_Key);
@@ -220,7 +234,6 @@ public class Key {
mX = Math.round(keyXPos + horizontalGap / 2);
mY = keyYPos;
mWidth = Math.round(keyWidth - horizontalGap);
- mHorizontalGap = Math.round(horizontalGap);
mHitBox.set(Math.round(keyXPos), keyYPos, Math.round(keyXPos + keyWidth) + 1,
keyYPos + keyHeight);
// Update row to have current x coordinate.
@@ -229,15 +242,15 @@ public class Key {
mBackgroundType = style.getInt(keyAttr,
R.styleable.Keyboard_Key_backgroundType, row.getDefaultBackgroundType());
- mVisualInsetsLeft = Math.round(Keyboard.Builder.getDimensionOrFraction(keyAttr,
+ final int visualInsetsLeft = Math.round(ResourceUtils.getDimensionOrFraction(keyAttr,
R.styleable.Keyboard_Key_visualInsetsLeft, params.mBaseWidth, 0));
- mVisualInsetsRight = Math.round(Keyboard.Builder.getDimensionOrFraction(keyAttr,
+ final int visualInsetsRight = Math.round(ResourceUtils.getDimensionOrFraction(keyAttr,
R.styleable.Keyboard_Key_visualInsetsRight, params.mBaseWidth, 0));
mIconId = KeySpecParser.getIconId(style.getString(keyAttr,
R.styleable.Keyboard_Key_keyIcon));
- mDisabledIconId = KeySpecParser.getIconId(style.getString(keyAttr,
+ final int disabledIconId = KeySpecParser.getIconId(style.getString(keyAttr,
R.styleable.Keyboard_Key_keyIconDisabled));
- mPreviewIconId = KeySpecParser.getIconId(style.getString(keyAttr,
+ final int previewIconId = KeySpecParser.getIconId(style.getString(keyAttr,
R.styleable.Keyboard_Key_keyIconPreview));
mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags)
@@ -331,11 +344,20 @@ public class Key {
} else {
mCode = KeySpecParser.toUpperCaseOfCodeForLocale(code, needsToUpperCase, locale);
}
- mOutputText = outputText;
- mAltCode = KeySpecParser.toUpperCaseOfCodeForLocale(
+ final int altCode = KeySpecParser.toUpperCaseOfCodeForLocale(
KeySpecParser.parseCode(style.getString(keyAttr,
R.styleable.Keyboard_Key_altCode), params.mCodesSet, CODE_UNSPECIFIED),
needsToUpperCase, locale);
+ if (outputText == null && altCode == CODE_UNSPECIFIED
+ && disabledIconId == ICON_UNDEFINED && previewIconId == ICON_UNDEFINED
+ && visualInsetsLeft == 0 && visualInsetsRight == 0) {
+ mOptionalAttributes = null;
+ } else {
+ mOptionalAttributes = new OptionalAttributes(outputText, altCode,
+ disabledIconId, previewIconId,
+ visualInsetsLeft, visualInsetsRight);
+ }
+
mHashCode = computeHashCode(this);
keyAttr.recycle();
@@ -345,7 +367,7 @@ public class Key {
}
}
- private static boolean needsToUpperCase(int labelFlags, int keyboardElementId) {
+ private static boolean needsToUpperCase(final int labelFlags, final int keyboardElementId) {
if ((labelFlags & LABEL_FLAGS_PRESERVE_CASE) != 0) return false;
switch (keyboardElementId) {
case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
@@ -358,7 +380,7 @@ public class Key {
}
}
- private static int computeHashCode(Key key) {
+ private static int computeHashCode(final Key key) {
return Arrays.hashCode(new Object[] {
key.mX,
key.mY,
@@ -370,22 +392,22 @@ public class Key {
key.mIconId,
key.mBackgroundType,
Arrays.hashCode(key.mMoreKeys),
- key.mOutputText,
+ key.getOutputText(),
key.mActionFlags,
key.mLabelFlags,
// Key can be distinguishable without the following members.
- // key.mAltCode,
- // key.mDisabledIconId,
- // key.mPreviewIconId,
+ // key.mOptionalAttributes.mAltCode,
+ // key.mOptionalAttributes.mDisabledIconId,
+ // key.mOptionalAttributes.mPreviewIconId,
// key.mHorizontalGap,
// key.mVerticalGap,
- // key.mVisualInsetLeft,
- // key.mVisualInsetRight,
+ // key.mOptionalAttributes.mVisualInsetLeft,
+ // key.mOptionalAttributes.mVisualInsetRight,
// key.mMaxMoreKeysColumn,
});
}
- private boolean equals(Key o) {
+ private boolean equals(final Key o) {
if (this == o) return true;
return o.mX == mX
&& o.mY == mY
@@ -397,7 +419,7 @@ public class Key {
&& o.mIconId == mIconId
&& o.mBackgroundType == mBackgroundType
&& Arrays.equals(o.mMoreKeys, mMoreKeys)
- && TextUtils.equals(o.mOutputText, mOutputText)
+ && TextUtils.equals(o.getOutputText(), getOutputText())
&& o.mActionFlags == mActionFlags
&& o.mLabelFlags == mLabelFlags;
}
@@ -408,7 +430,7 @@ public class Key {
}
@Override
- public boolean equals(Object o) {
+ public boolean equals(final Object o) {
return o instanceof Key && equals((Key)o);
}
@@ -425,7 +447,7 @@ public class Key {
KeyboardIconsSet.getIconName(mIconId), backgroundName(mBackgroundType));
}
- private static String backgroundName(int backgroundType) {
+ private static String backgroundName(final int backgroundType) {
switch (backgroundType) {
case BACKGROUND_TYPE_NORMAL: return "normal";
case BACKGROUND_TYPE_FUNCTIONAL: return "functional";
@@ -436,19 +458,19 @@ public class Key {
}
}
- public void markAsLeftEdge(Keyboard.Params params) {
+ public void markAsLeftEdge(final KeyboardParams params) {
mHitBox.left = params.mHorizontalEdgesPadding;
}
- public void markAsRightEdge(Keyboard.Params params) {
+ public void markAsRightEdge(final KeyboardParams params) {
mHitBox.right = params.mOccupiedWidth - params.mHorizontalEdgesPadding;
}
- public void markAsTopEdge(Keyboard.Params params) {
+ public void markAsTopEdge(final KeyboardParams params) {
mHitBox.top = params.mTopPadding;
}
- public void markAsBottomEdge(Keyboard.Params params) {
+ public void markAsBottomEdge(final KeyboardParams params) {
mHitBox.bottom = params.mOccupiedHeight + params.mBottomPadding;
}
@@ -482,7 +504,7 @@ public class Key {
&& (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) == 0;
}
- public Typeface selectTypeface(Typeface defaultTypeface) {
+ public Typeface selectTypeface(final Typeface defaultTypeface) {
// TODO: Handle "bold" here too?
if ((mLabelFlags & LABEL_FLAGS_FONT_NORMAL) != 0) {
return Typeface.DEFAULT;
@@ -493,8 +515,8 @@ public class Key {
}
}
- public int selectTextSize(int letterSize, int largeLetterSize, int labelSize,
- int largeLabelSize, int hintLabelSize) {
+ public int selectTextSize(final int letterSize, final int largeLetterSize, final int labelSize,
+ final int largeLabelSize, final int hintLabelSize) {
switch (mLabelFlags & LABEL_FLAGS_FOLLOW_KEY_TEXT_RATIO_MASK) {
case LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO:
return letterSize;
@@ -577,8 +599,20 @@ public class Key {
return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_EMBEDDED_MORE_KEY) != 0;
}
- public Drawable getIcon(KeyboardIconsSet iconSet, int alpha) {
- final int iconId = mEnabled ? mIconId : mDisabledIconId;
+ public String getOutputText() {
+ final OptionalAttributes attrs = mOptionalAttributes;
+ return (attrs != null) ? attrs.mOutputText : null;
+ }
+
+ public int getAltCode() {
+ final OptionalAttributes attrs = mOptionalAttributes;
+ return (attrs != null) ? attrs.mAltCode : CODE_UNSPECIFIED;
+ }
+
+ public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
+ final OptionalAttributes attrs = mOptionalAttributes;
+ final int disabledIconId = (attrs != null) ? attrs.mDisabledIconId : ICON_UNDEFINED;
+ final int iconId = mEnabled ? mIconId : disabledIconId;
final Drawable icon = iconSet.getIconDrawable(iconId);
if (icon != null) {
icon.setAlpha(alpha);
@@ -586,10 +620,22 @@ public class Key {
return icon;
}
- public Drawable getPreviewIcon(KeyboardIconsSet iconSet) {
- return mPreviewIconId != ICON_UNDEFINED
- ? iconSet.getIconDrawable(mPreviewIconId)
- : iconSet.getIconDrawable(mIconId);
+ public Drawable getPreviewIcon(final KeyboardIconsSet iconSet) {
+ final OptionalAttributes attrs = mOptionalAttributes;
+ final int previewIconId = (attrs != null) ? attrs.mPreviewIconId : ICON_UNDEFINED;
+ return previewIconId != ICON_UNDEFINED
+ ? iconSet.getIconDrawable(previewIconId) : iconSet.getIconDrawable(mIconId);
+ }
+
+ public int getDrawX() {
+ final OptionalAttributes attrs = mOptionalAttributes;
+ return (attrs == null) ? mX : mX + attrs.mVisualInsetsLeft;
+ }
+
+ public int getDrawWidth() {
+ final OptionalAttributes attrs = mOptionalAttributes;
+ return (attrs == null) ? mWidth
+ : mWidth - attrs.mVisualInsetsLeft - attrs.mVisualInsetsRight;
}
/**
@@ -614,7 +660,7 @@ public class Key {
return mEnabled;
}
- public void setEnabled(boolean enabled) {
+ public void setEnabled(final boolean enabled) {
mEnabled = enabled;
}
@@ -624,9 +670,9 @@ public class Key {
* @param y the y-coordinate of the point
* @return whether or not the point falls on the key. If the key is attached to an edge, it
* will assume that all points between the key and the edge are considered to be on the key.
- * @see #markAsLeftEdge(Keyboard.Params) etc.
+ * @see #markAsLeftEdge(KeyboardParams) etc.
*/
- public boolean isOnKey(int x, int y) {
+ public boolean isOnKey(final int x, final int y) {
return mHitBox.contains(x, y);
}
@@ -636,7 +682,7 @@ public class Key {
* @param y the y-coordinate of the point
* @return the square of the distance of the point from the nearest edge of the key
*/
- public int squaredDistanceToEdge(int x, int y) {
+ public int squaredDistanceToEdge(final int x, final int y) {
final int left = mX;
final int right = left + mWidth;
final int top = mY;
@@ -718,15 +764,16 @@ public class Key {
}
public static class Spacer extends Key {
- public Spacer(Resources res, Keyboard.Params params, Keyboard.Builder.Row row,
- XmlPullParser parser) throws XmlPullParserException {
+ public Spacer(final Resources res, final KeyboardParams params, final KeyboardRow row,
+ final XmlPullParser parser) throws XmlPullParserException {
super(res, params, row, parser);
}
/**
* This constructor is being used only for divider in more keys keyboard.
*/
- protected Spacer(Keyboard.Params params, int x, int y, int width, int height) {
+ protected Spacer(final KeyboardParams params, final int x, final int y, final int width,
+ final int height) {
super(params, null, null, ICON_UNDEFINED, CODE_UNSPECIFIED,
null, x, y, width, height, 0);
}
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index a5f9e9e75..c1b007d2e 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -16,40 +16,15 @@
package com.android.inputmethod.keyboard;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
import android.graphics.Typeface;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.util.TypedValue;
-import android.util.Xml;
-import android.view.InflateException;
-import com.android.inputmethod.keyboard.internal.KeyStyles;
-import com.android.inputmethod.keyboard.internal.KeyboardCodesSet;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
-import com.android.inputmethod.keyboard.internal.KeyboardTextsSet;
+import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.latin.CollectionUtils;
-import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
-import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResourceUtils;
-import com.android.inputmethod.latin.SubtypeLocale;
-import com.android.inputmethod.latin.XmlParseUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Locale;
/**
* Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
@@ -123,6 +98,10 @@ public class Keyboard {
/** Per keyboard key visual parameters */
public final Typeface mKeyTypeface;
+ public final float mKeyLetterRatio;
+ public final int mKeyLetterSize;
+ public final float mKeyHintLetterRatio;
+ public final float mKeyShiftedLetterHintRatio;
public final int mMostCommonKeyHeight;
public final int mMostCommonKeyWidth;
@@ -144,7 +123,7 @@ public class Keyboard {
private final ProximityInfo mProximityInfo;
private final boolean mProximityCharsCorrectionEnabled;
- public Keyboard(Params params) {
+ public Keyboard(final KeyboardParams params) {
mId = params.mId;
mThemeId = params.mThemeId;
mOccupiedHeight = params.mOccupiedHeight;
@@ -155,6 +134,10 @@ public class Keyboard {
mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn;
mKeyTypeface = params.mKeyTypeface;
+ mKeyLetterRatio = params.mKeyLetterRatio;
+ mKeyLetterSize = params.mKeyLetterSize;
+ mKeyHintLetterRatio = params.mKeyHintLetterRatio;
+ mKeyShiftedLetterHintRatio = params.mKeyShiftedLetterHintRatio;
mTopPadding = params.mTopPadding;
mVerticalGap = params.mVerticalGap;
@@ -171,7 +154,7 @@ public class Keyboard {
mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
}
- public boolean hasProximityCharsCorrection(int code) {
+ public boolean hasProximityCharsCorrection(final int code) {
if (!mProximityCharsCorrectionEnabled) {
return false;
}
@@ -187,7 +170,7 @@ public class Keyboard {
return mProximityInfo;
}
- public Key getKey(int code) {
+ public Key getKey(final int code) {
if (code == CODE_UNSPECIFIED) {
return null;
}
@@ -208,7 +191,7 @@ public class Keyboard {
}
}
- public boolean hasKey(Key aKey) {
+ public boolean hasKey(final Key aKey) {
if (mKeyCache.indexOfValue(aKey) >= 0) {
return true;
}
@@ -222,7 +205,7 @@ public class Keyboard {
return false;
}
- public static boolean isLetterCode(int code) {
+ public static boolean isLetterCode(final int code) {
return code >= CODE_SPACE;
}
@@ -231,174 +214,6 @@ public class Keyboard {
return mId.toString();
}
- // TODO: Move this class to internal package
- public static class Params {
- public KeyboardId mId;
- public int mThemeId;
-
- /** Total height and width of the keyboard, including the paddings and keys */
- public int mOccupiedHeight;
- public int mOccupiedWidth;
-
- /** Base height and width of the keyboard used to calculate rows' or keys' heights and
- * widths
- */
- public int mBaseHeight;
- public int mBaseWidth;
-
- public int mTopPadding;
- public int mBottomPadding;
- public int mHorizontalEdgesPadding;
- public int mHorizontalCenterPadding;
-
- public Typeface mKeyTypeface = null;
-
- public int mDefaultRowHeight;
- public int mDefaultKeyWidth;
- public int mHorizontalGap;
- public int mVerticalGap;
-
- public int mMoreKeysTemplate;
- public int mMaxMoreKeysKeyboardColumn;
-
- public int GRID_WIDTH;
- public int GRID_HEIGHT;
-
- public final HashSet<Key> mKeys = CollectionUtils.newHashSet();
- public final ArrayList<Key> mShiftKeys = CollectionUtils.newArrayList();
- public final ArrayList<Key> mAltCodeKeysWhileTyping = CollectionUtils.newArrayList();
- public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
- public final KeyboardCodesSet mCodesSet = new KeyboardCodesSet();
- public final KeyboardTextsSet mTextsSet = new KeyboardTextsSet();
- public final KeyStyles mKeyStyles = new KeyStyles(mTextsSet);
-
- public KeyboardLayoutSet.KeysCache mKeysCache;
-
- public int mMostCommonKeyHeight = 0;
- public int mMostCommonKeyWidth = 0;
-
- public boolean mProximityCharsCorrectionEnabled;
-
- public final TouchPositionCorrection mTouchPositionCorrection =
- new TouchPositionCorrection();
-
- public static class TouchPositionCorrection {
- private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3;
-
- public boolean mEnabled;
- public float[] mXs;
- public float[] mYs;
- public float[] mRadii;
-
- public void load(String[] data) {
- final int dataLength = data.length;
- if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
- if (LatinImeLogger.sDBG) {
- throw new RuntimeException(
- "the size of touch position correction data is invalid");
- }
- return;
- }
-
- final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
- mXs = new float[length];
- mYs = new float[length];
- mRadii = new float[length];
- try {
- for (int i = 0; i < dataLength; ++i) {
- final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE;
- final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
- final float value = Float.parseFloat(data[i]);
- if (type == 0) {
- mXs[index] = value;
- } else if (type == 1) {
- mYs[index] = value;
- } else {
- mRadii[index] = value;
- }
- }
- } catch (NumberFormatException e) {
- if (LatinImeLogger.sDBG) {
- throw new RuntimeException(
- "the number format for touch position correction data is invalid");
- }
- mXs = null;
- mYs = null;
- mRadii = null;
- }
- }
-
- // TODO: Remove this method.
- public void setEnabled(boolean enabled) {
- mEnabled = enabled;
- }
-
- public boolean isValid() {
- return mEnabled && mXs != null && mYs != null && mRadii != null
- && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
- }
- }
-
- protected void clearKeys() {
- mKeys.clear();
- mShiftKeys.clear();
- clearHistogram();
- }
-
- public void onAddKey(Key newKey) {
- final Key key = (mKeysCache != null) ? mKeysCache.get(newKey) : newKey;
- final boolean zeroWidthSpacer = key.isSpacer() && key.mWidth == 0;
- if (!zeroWidthSpacer) {
- mKeys.add(key);
- updateHistogram(key);
- }
- if (key.mCode == Keyboard.CODE_SHIFT) {
- mShiftKeys.add(key);
- }
- if (key.altCodeWhileTyping()) {
- mAltCodeKeysWhileTyping.add(key);
- }
- }
-
- private int mMaxHeightCount = 0;
- private int mMaxWidthCount = 0;
- private final SparseIntArray mHeightHistogram = new SparseIntArray();
- private final SparseIntArray mWidthHistogram = new SparseIntArray();
-
- private void clearHistogram() {
- mMostCommonKeyHeight = 0;
- mMaxHeightCount = 0;
- mHeightHistogram.clear();
-
- mMaxWidthCount = 0;
- mMostCommonKeyWidth = 0;
- mWidthHistogram.clear();
- }
-
- private static int updateHistogramCounter(SparseIntArray histogram, int key) {
- final int index = histogram.indexOfKey(key);
- final int count = (index >= 0 ? histogram.get(key) : 0) + 1;
- histogram.put(key, count);
- return count;
- }
-
- private void updateHistogram(Key key) {
- final int height = key.mHeight + key.mVerticalGap;
- final int heightCount = updateHistogramCounter(mHeightHistogram, height);
- if (heightCount > mMaxHeightCount) {
- mMaxHeightCount = heightCount;
- mMostCommonKeyHeight = height;
- }
-
- final int width = key.mWidth + key.mHorizontalGap;
- final int widthCount = updateHistogramCounter(mWidthHistogram, width);
- if (widthCount > mMaxWidthCount) {
- mMaxWidthCount = widthCount;
- mMostCommonKeyWidth = width;
- }
- }
- }
-
/**
* Returns the array of the keys that are closest to the given point.
* @param x the x-coordinate of the point
@@ -406,14 +221,14 @@ public class Keyboard {
* @return the array of the nearest keys to the given point. If the given
* point is out of range, then an array of size zero is returned.
*/
- public Key[] getNearestKeys(int x, int y) {
+ public Key[] getNearestKeys(final int x, final int y) {
// Avoid dead pixels at edges of the keyboard
final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
}
- public static String printableCode(int code) {
+ public static String printableCode(final int code) {
switch (code) {
case CODE_SHIFT: return "shift";
case CODE_SWITCH_ALPHA_SYMBOL: return "symbol";
@@ -435,953 +250,4 @@ public class Keyboard {
return String.format("'\\u%04x'", code);
}
}
-
- /**
- * Keyboard Building helper.
- *
- * This class parses Keyboard XML file and eventually build a Keyboard.
- * The Keyboard XML file looks like:
- * <pre>
- * &lt;!-- xml/keyboard.xml --&gt;
- * &lt;Keyboard keyboard_attributes*&gt;
- * &lt;!-- Keyboard Content --&gt;
- * &lt;Row row_attributes*&gt;
- * &lt;!-- Row Content --&gt;
- * &lt;Key key_attributes* /&gt;
- * &lt;Spacer horizontalGap="32.0dp" /&gt;
- * &lt;include keyboardLayout="@xml/other_keys"&gt;
- * ...
- * &lt;/Row&gt;
- * &lt;include keyboardLayout="@xml/other_rows"&gt;
- * ...
- * &lt;/Keyboard&gt;
- * </pre>
- * The XML file which is included in other file must have &lt;merge&gt; as root element,
- * such as:
- * <pre>
- * &lt;!-- xml/other_keys.xml --&gt;
- * &lt;merge&gt;
- * &lt;Key key_attributes* /&gt;
- * ...
- * &lt;/merge&gt;
- * </pre>
- * and
- * <pre>
- * &lt;!-- xml/other_rows.xml --&gt;
- * &lt;merge&gt;
- * &lt;Row row_attributes*&gt;
- * &lt;Key key_attributes* /&gt;
- * &lt;/Row&gt;
- * ...
- * &lt;/merge&gt;
- * </pre>
- * You can also use switch-case-default tags to select Rows and Keys.
- * <pre>
- * &lt;switch&gt;
- * &lt;case case_attribute*&gt;
- * &lt;!-- Any valid tags at switch position --&gt;
- * &lt;/case&gt;
- * ...
- * &lt;default&gt;
- * &lt;!-- Any valid tags at switch position --&gt;
- * &lt;/default&gt;
- * &lt;/switch&gt;
- * </pre>
- * You can declare Key style and specify styles within Key tags.
- * <pre>
- * &lt;switch&gt;
- * &lt;case mode="email"&gt;
- * &lt;key-style styleName="f1-key" parentStyle="modifier-key"
- * keyLabel=".com"
- * /&gt;
- * &lt;/case&gt;
- * &lt;case mode="url"&gt;
- * &lt;key-style styleName="f1-key" parentStyle="modifier-key"
- * keyLabel="http://"
- * /&gt;
- * &lt;/case&gt;
- * &lt;/switch&gt;
- * ...
- * &lt;Key keyStyle="shift-key" ... /&gt;
- * </pre>
- */
-
- // TODO: Move this class to internal package.
- public static class Builder<KP extends Params> {
- private static final String BUILDER_TAG = "Keyboard.Builder";
- private static final boolean DEBUG = false;
-
- // Keyboard XML Tags
- private static final String TAG_KEYBOARD = "Keyboard";
- private static final String TAG_ROW = "Row";
- private static final String TAG_KEY = "Key";
- private static final String TAG_SPACER = "Spacer";
- private static final String TAG_INCLUDE = "include";
- private static final String TAG_MERGE = "merge";
- private static final String TAG_SWITCH = "switch";
- private static final String TAG_CASE = "case";
- private static final String TAG_DEFAULT = "default";
- public static final String TAG_KEY_STYLE = "key-style";
-
- private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
- private static final int DEFAULT_KEYBOARD_ROWS = 4;
-
- protected final KP mParams;
- protected final Context mContext;
- protected final Resources mResources;
- private final DisplayMetrics mDisplayMetrics;
-
- private int mCurrentY = 0;
- private Row mCurrentRow = null;
- private boolean mLeftEdge;
- private boolean mTopEdge;
- private Key mRightEdgeKey = null;
-
- /**
- * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
- * Some of the key size defaults can be overridden per row from what the {@link Keyboard}
- * defines.
- */
- public static class Row {
- // keyWidth enum constants
- private static final int KEYWIDTH_NOT_ENUM = 0;
- private static final int KEYWIDTH_FILL_RIGHT = -1;
-
- private final Params mParams;
- /** Default width of a key in this row. */
- private float mDefaultKeyWidth;
- /** Default height of a key in this row. */
- public final int mRowHeight;
- /** Default keyLabelFlags in this row. */
- private int mDefaultKeyLabelFlags;
- /** Default backgroundType for this row */
- private int mDefaultBackgroundType;
-
- private final int mCurrentY;
- // Will be updated by {@link Key}'s constructor.
- private float mCurrentX;
-
- public Row(Resources res, Params params, XmlPullParser parser, int y) {
- mParams = params;
- TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard);
- mRowHeight = (int)Builder.getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_rowHeight,
- params.mBaseHeight, params.mDefaultRowHeight);
- keyboardAttr.recycle();
- TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Key);
- mDefaultKeyWidth = Builder.getDimensionOrFraction(keyAttr,
- R.styleable.Keyboard_Key_keyWidth,
- params.mBaseWidth, params.mDefaultKeyWidth);
- mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType,
- Key.BACKGROUND_TYPE_NORMAL);
- keyAttr.recycle();
-
- // TODO: Initialize this with <Row> attribute as backgroundType is done.
- mDefaultKeyLabelFlags = 0;
- mCurrentY = y;
- mCurrentX = 0.0f;
- }
-
- public float getDefaultKeyWidth() {
- return mDefaultKeyWidth;
- }
-
- public void setDefaultKeyWidth(float defaultKeyWidth) {
- mDefaultKeyWidth = defaultKeyWidth;
- }
-
- public int getDefaultKeyLabelFlags() {
- return mDefaultKeyLabelFlags;
- }
-
- public void setDefaultKeyLabelFlags(int keyLabelFlags) {
- mDefaultKeyLabelFlags = keyLabelFlags;
- }
-
- public int getDefaultBackgroundType() {
- return mDefaultBackgroundType;
- }
-
- public void setDefaultBackgroundType(int backgroundType) {
- mDefaultBackgroundType = backgroundType;
- }
-
- public void setXPos(float keyXPos) {
- mCurrentX = keyXPos;
- }
-
- public void advanceXPos(float width) {
- mCurrentX += width;
- }
-
- public int getKeyY() {
- return mCurrentY;
- }
-
- public float getKeyX(TypedArray keyAttr) {
- final int keyboardRightEdge = mParams.mOccupiedWidth
- - mParams.mHorizontalEdgesPadding;
- if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
- final float keyXPos = Builder.getDimensionOrFraction(keyAttr,
- R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0);
- if (keyXPos < 0) {
- // If keyXPos is negative, the actual x-coordinate will be
- // keyboardWidth + keyXPos.
- // keyXPos shouldn't be less than mCurrentX because drawable area for this
- // key starts at mCurrentX. Or, this key will overlaps the adjacent key on
- // its left hand side.
- return Math.max(keyXPos + keyboardRightEdge, mCurrentX);
- } else {
- return keyXPos + mParams.mHorizontalEdgesPadding;
- }
- }
- return mCurrentX;
- }
-
- public float getKeyWidth(TypedArray keyAttr) {
- return getKeyWidth(keyAttr, mCurrentX);
- }
-
- public float getKeyWidth(TypedArray keyAttr, float keyXPos) {
- final int widthType = Builder.getEnumValue(keyAttr,
- R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
- switch (widthType) {
- case KEYWIDTH_FILL_RIGHT:
- final int keyboardRightEdge =
- mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding;
- // If keyWidth is fillRight, the actual key width will be determined to fill
- // out the area up to the right edge of the keyboard.
- return keyboardRightEdge - keyXPos;
- default: // KEYWIDTH_NOT_ENUM
- return Builder.getDimensionOrFraction(keyAttr,
- R.styleable.Keyboard_Key_keyWidth,
- mParams.mBaseWidth, mDefaultKeyWidth);
- }
- }
- }
-
- public Builder(Context context, KP params) {
- mContext = context;
- final Resources res = context.getResources();
- mResources = res;
- mDisplayMetrics = res.getDisplayMetrics();
-
- mParams = params;
-
- params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
- params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
- }
-
- public void setAutoGenerate(KeyboardLayoutSet.KeysCache keysCache) {
- mParams.mKeysCache = keysCache;
- }
-
- public Builder<KP> load(int xmlId, KeyboardId id) {
- mParams.mId = id;
- final XmlResourceParser parser = mResources.getXml(xmlId);
- try {
- parseKeyboard(parser);
- } catch (XmlPullParserException e) {
- Log.w(BUILDER_TAG, "keyboard XML parse error: " + e);
- throw new IllegalArgumentException(e);
- } catch (IOException e) {
- Log.w(BUILDER_TAG, "keyboard XML parse error: " + e);
- throw new RuntimeException(e);
- } finally {
- parser.close();
- }
- return this;
- }
-
- // TODO: Remove this method.
- public void setTouchPositionCorrectionEnabled(boolean enabled) {
- mParams.mTouchPositionCorrection.setEnabled(enabled);
- }
-
- public void setProximityCharsCorrectionEnabled(boolean enabled) {
- mParams.mProximityCharsCorrectionEnabled = enabled;
- }
-
- public Keyboard build() {
- 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) startTag("<%s> %s", TAG_KEYBOARD, mParams.mId);
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_KEYBOARD.equals(tag)) {
- parseKeyboardAttributes(parser);
- startKeyboard();
- parseKeyboardContent(parser, false);
- break;
- } else {
- throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD);
- }
- }
- }
- }
-
- private void parseKeyboardAttributes(XmlPullParser parser) {
- final int displayWidth = mDisplayMetrics.widthPixels;
- final TypedArray keyboardAttr = mContext.obtainStyledAttributes(
- Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle,
- R.style.Keyboard);
- final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Key);
- final TypedArray keyboardViewAttr = mResources.obtainAttributes(
- Xml.asAttributeSet(parser), R.styleable.KeyboardView);
- try {
- final int displayHeight = mDisplayMetrics.heightPixels;
- final String keyboardHeightString = ResourceUtils.getDeviceOverrideValue(
- mResources, R.array.keyboard_heights, null);
- final float keyboardHeight;
- if (keyboardHeightString != null) {
- keyboardHeight = Float.parseFloat(keyboardHeightString)
- * mDisplayMetrics.density;
- } else {
- keyboardHeight = keyboardAttr.getDimension(
- R.styleable.Keyboard_keyboardHeight, displayHeight / 2);
- }
- final float maxKeyboardHeight = getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2);
- float minKeyboardHeight = getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2);
- if (minKeyboardHeight < 0) {
- // Specified fraction was negative, so it should be calculated against display
- // width.
- minKeyboardHeight = -getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2);
- }
- final Params params = mParams;
- // Keyboard height will not exceed maxKeyboardHeight and will not be less than
- // minKeyboardHeight.
- params.mOccupiedHeight = (int)Math.max(
- Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
- params.mOccupiedWidth = params.mId.mWidth;
- params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0);
- params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0);
- params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_keyboardHorizontalEdgesPadding,
- mParams.mOccupiedWidth, 0);
-
- params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2
- - params.mHorizontalCenterPadding;
- params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr,
- R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth,
- params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS);
- params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0);
- params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0);
- params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding
- - params.mBottomPadding + params.mVerticalGap;
- params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_rowHeight, params.mBaseHeight,
- params.mBaseHeight / DEFAULT_KEYBOARD_ROWS);
-
- if (keyboardViewAttr.hasValue(R.styleable.KeyboardView_keyTypeface)) {
- params.mKeyTypeface = Typeface.defaultFromStyle(keyboardViewAttr.getInt(
- R.styleable.KeyboardView_keyTypeface, Typeface.NORMAL));
- }
-
- params.mMoreKeysTemplate = keyboardAttr.getResourceId(
- R.styleable.Keyboard_moreKeysTemplate, 0);
- params.mMaxMoreKeysKeyboardColumn = keyAttr.getInt(
- R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);
-
- params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0);
- params.mIconsSet.loadIcons(keyboardAttr);
- final String language = params.mId.mLocale.getLanguage();
- params.mCodesSet.setLanguage(language);
- params.mTextsSet.setLanguage(language);
- final RunInLocale<Void> job = new RunInLocale<Void>() {
- @Override
- protected Void job(Resources res) {
- params.mTextsSet.loadStringResources(mContext);
- return null;
- }
- };
- // Null means the current system locale.
- final Locale locale = SubtypeLocale.isNoLanguage(params.mId.mSubtype)
- ? null : params.mId.mLocale;
- job.runInLocale(mResources, locale);
-
- final int resourceId = keyboardAttr.getResourceId(
- R.styleable.Keyboard_touchPositionCorrectionData, 0);
- params.mTouchPositionCorrection.setEnabled(resourceId != 0);
- if (resourceId != 0) {
- final String[] data = mResources.getStringArray(resourceId);
- params.mTouchPositionCorrection.load(data);
- }
- } finally {
- keyboardViewAttr.recycle();
- keyAttr.recycle();
- keyboardAttr.recycle();
- }
- }
-
- private void parseKeyboardContent(XmlPullParser parser, boolean skip)
- throws XmlPullParserException, IOException {
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_ROW.equals(tag)) {
- Row row = parseRowAttributes(parser);
- 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);
- } else if (TAG_SWITCH.equals(tag)) {
- parseSwitchKeyboardContent(parser, skip);
- } else if (TAG_KEY_STYLE.equals(tag)) {
- parseKeyStyle(parser, skip);
- } else {
- throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW);
- }
- } 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)) {
- break;
- } else {
- throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW);
- }
- }
- }
- }
-
- private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException {
- final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard);
- try {
- if (a.hasValue(R.styleable.Keyboard_horizontalGap)) {
- throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap");
- }
- if (a.hasValue(R.styleable.Keyboard_verticalGap)) {
- throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap");
- }
- return new Row(mResources, mParams, parser, mCurrentY);
- } finally {
- a.recycle();
- }
- }
-
- private void parseRowContent(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_KEY.equals(tag)) {
- parseKey(parser, row, skip);
- } else if (TAG_SPACER.equals(tag)) {
- parseSpacer(parser, row, skip);
- } else if (TAG_INCLUDE.equals(tag)) {
- parseIncludeRowContent(parser, row, skip);
- } else if (TAG_SWITCH.equals(tag)) {
- parseSwitchRowContent(parser, row, skip);
- } else if (TAG_KEY_STYLE.equals(tag)) {
- parseKeyStyle(parser, skip);
- } else {
- throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
- }
- } else if (event == XmlPullParser.END_TAG) {
- final String tag = parser.getName();
- if (DEBUG) endTag("</%s>", tag);
- if (TAG_ROW.equals(tag)) {
- if (!skip) {
- endRow(row);
- }
- break;
- } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)
- || TAG_MERGE.equals(tag)) {
- break;
- } else {
- throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
- }
- }
- }
- }
-
- private void parseKey(XmlPullParser parser, Row row, boolean skip)
- 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);
- 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);
- }
- }
-
- private void parseSpacer(XmlPullParser parser, Row row, boolean skip)
- 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);
- if (DEBUG) startEndTag("<%s />", TAG_SPACER);
- XmlParseUtils.checkEndTag(TAG_SPACER, parser);
- endKey(spacer);
- }
- }
-
- private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip)
- throws XmlPullParserException, IOException {
- parseIncludeInternal(parser, null, skip);
- }
-
- private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- parseIncludeInternal(parser, row, skip);
- }
-
- private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip)
- 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,
- R.styleable.Keyboard_Include);
- final TypedArray keyAttr = mResources.obtainAttributes(attr,
- R.styleable.Keyboard_Key);
- int keyboardLayout = 0;
- float savedDefaultKeyWidth = 0;
- int savedDefaultKeyLabelFlags = 0;
- int savedDefaultBackgroundType = Key.BACKGROUND_TYPE_NORMAL;
- try {
- XmlParseUtils.checkAttributeExists(keyboardAttr,
- R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout",
- TAG_INCLUDE, parser);
- keyboardLayout = keyboardAttr.getResourceId(
- R.styleable.Keyboard_Include_keyboardLayout, 0);
- if (row != null) {
- if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
- // Override current x coordinate.
- row.setXPos(row.getKeyX(keyAttr));
- }
- // TODO: Remove this if-clause and do the same as backgroundType below.
- savedDefaultKeyWidth = row.getDefaultKeyWidth();
- if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyWidth)) {
- // Override default key width.
- row.setDefaultKeyWidth(row.getKeyWidth(keyAttr));
- }
- savedDefaultKeyLabelFlags = row.getDefaultKeyLabelFlags();
- // Bitwise-or default keyLabelFlag if exists.
- row.setDefaultKeyLabelFlags(keyAttr.getInt(
- R.styleable.Keyboard_Key_keyLabelFlags, 0)
- | savedDefaultKeyLabelFlags);
- savedDefaultBackgroundType = row.getDefaultBackgroundType();
- // Override default backgroundType if exists.
- row.setDefaultBackgroundType(keyAttr.getInt(
- R.styleable.Keyboard_Key_backgroundType,
- savedDefaultBackgroundType));
- }
- } finally {
- keyboardAttr.recycle();
- keyAttr.recycle();
- }
-
- XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
- if (DEBUG) {
- startEndTag("<%s keyboardLayout=%s />",TAG_INCLUDE,
- mResources.getResourceEntryName(keyboardLayout));
- }
- final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout);
- try {
- parseMerge(parserForInclude, row, skip);
- } finally {
- if (row != null) {
- // Restore default keyWidth, keyLabelFlags, and backgroundType.
- row.setDefaultKeyWidth(savedDefaultKeyWidth);
- row.setDefaultKeyLabelFlags(savedDefaultKeyLabelFlags);
- row.setDefaultBackgroundType(savedDefaultBackgroundType);
- }
- parserForInclude.close();
- }
- }
- }
-
- 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) {
- final String tag = parser.getName();
- if (TAG_MERGE.equals(tag)) {
- if (row == null) {
- parseKeyboardContent(parser, skip);
- } else {
- parseRowContent(parser, row, skip);
- }
- break;
- } else {
- throw new XmlParseUtils.ParseException(
- "Included keyboard layout must have <merge> root element", parser);
- }
- }
- }
- }
-
- private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip)
- throws XmlPullParserException, IOException {
- parseSwitchInternal(parser, null, skip);
- }
-
- private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- parseSwitchInternal(parser, row, skip);
- }
-
- private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- if (DEBUG) startTag("<%s> %s", TAG_SWITCH, mParams.mId);
- boolean selected = false;
- int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (event == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- if (TAG_CASE.equals(tag)) {
- selected |= parseCase(parser, row, selected ? true : skip);
- } else if (TAG_DEFAULT.equals(tag)) {
- selected |= parseDefault(parser, row, selected ? true : skip);
- } else {
- throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
- }
- } else if (event == XmlPullParser.END_TAG) {
- final String tag = parser.getName();
- if (TAG_SWITCH.equals(tag)) {
- if (DEBUG) endTag("</%s>", TAG_SWITCH);
- break;
- } else {
- throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
- }
- }
- }
- }
-
- private boolean parseCase(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- final boolean selected = parseCaseCondition(parser);
- if (row == null) {
- // Processing Rows.
- parseKeyboardContent(parser, selected ? skip : true);
- } else {
- // Processing Keys.
- parseRowContent(parser, row, selected ? skip : true);
- }
- return selected;
- }
-
- private boolean parseCaseCondition(XmlPullParser parser) {
- final KeyboardId id = mParams.mId;
- if (id == null) {
- return true;
- }
- final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Case);
- try {
- final boolean keyboardLayoutSetElementMatched = matchTypedValue(a,
- R.styleable.Keyboard_Case_keyboardLayoutSetElement, id.mElementId,
- KeyboardId.elementIdToName(id.mElementId));
- final boolean modeMatched = matchTypedValue(a,
- R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode));
- final boolean navigateNextMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_navigateNext, id.navigateNext());
- final boolean navigatePreviousMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_navigatePrevious, id.navigatePrevious());
- final boolean passwordInputMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_passwordInput, id.passwordInput());
- final boolean clobberSettingsKeyMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey);
- final boolean shortcutKeyEnabledMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled);
- final boolean hasShortcutKeyMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey);
- final boolean languageSwitchKeyEnabledMatched = matchBoolean(a,
- R.styleable.Keyboard_Case_languageSwitchKeyEnabled,
- id.mLanguageSwitchKeyEnabled);
- 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,
- R.styleable.Keyboard_Case_localeCode, id.mLocale.toString());
- final boolean languageCodeMatched = matchString(a,
- R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
- final boolean countryCodeMatched = matchString(a,
- R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
- final boolean selected = keyboardLayoutSetElementMatched && modeMatched
- && navigateNextMatched && navigatePreviousMatched && passwordInputMatched
- && clobberSettingsKeyMatched && shortcutKeyEnabledMatched
- && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched
- && 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_keyboardLayoutSetElement),
- "keyboardLayoutSetElement"),
- textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"),
- textAttr(a.getString(R.styleable.Keyboard_Case_imeAction),
- "imeAction"),
- booleanAttr(a, R.styleable.Keyboard_Case_navigateNext,
- "navigateNext"),
- booleanAttr(a, R.styleable.Keyboard_Case_navigatePrevious,
- "navigatePrevious"),
- booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey,
- "clobberSettingsKey"),
- booleanAttr(a, R.styleable.Keyboard_Case_passwordInput,
- "passwordInput"),
- booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled,
- "shortcutKeyEnabled"),
- booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey,
- "hasShortcutKey"),
- booleanAttr(a, R.styleable.Keyboard_Case_languageSwitchKeyEnabled,
- "languageSwitchKeyEnabled"),
- booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine,
- "isMultiLine"),
- 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 {
- a.recycle();
- }
- }
-
- private static boolean matchInteger(TypedArray a, int index, int value) {
- // If <case> does not have "index" attribute, that means this <case> is wild-card for
- // the attribute.
- return !a.hasValue(index) || a.getInt(index, 0) == value;
- }
-
- private static boolean matchBoolean(TypedArray a, int index, boolean value) {
- // If <case> does not have "index" attribute, that means this <case> is wild-card for
- // the attribute.
- return !a.hasValue(index) || a.getBoolean(index, false) == value;
- }
-
- private static boolean matchString(TypedArray a, int index, String value) {
- // If <case> does not have "index" attribute, that means this <case> is wild-card for
- // the attribute.
- return !a.hasValue(index)
- || stringArrayContains(a.getString(index).split("\\|"), value);
- }
-
- private static boolean matchTypedValue(TypedArray a, int index, int intValue,
- String strValue) {
- // If <case> does not have "index" attribute, that means this <case> is wild-card for
- // the attribute.
- final TypedValue v = a.peekValue(index);
- if (v == null) {
- return true;
- }
- if (isIntegerValue(v)) {
- return intValue == a.getInt(index, 0);
- } else if (isStringValue(v)) {
- return stringArrayContains(a.getString(index).split("\\|"), strValue);
- }
- return false;
- }
-
- private static boolean stringArrayContains(String[] array, String value) {
- for (final String elem : array) {
- if (elem.equals(value)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean parseDefault(XmlPullParser parser, Row row, boolean skip)
- throws XmlPullParserException, IOException {
- if (DEBUG) startTag("<%s>", TAG_DEFAULT);
- if (row == null) {
- parseKeyboardContent(parser, skip);
- } else {
- parseRowContent(parser, row, skip);
- }
- return true;
- }
-
- private void parseKeyStyle(XmlPullParser parser, boolean skip)
- throws XmlPullParserException, IOException {
- TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_KeyStyle);
- TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.Keyboard_Key);
- try {
- 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) {
- mParams.mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
- }
- } finally {
- keyStyleAttr.recycle();
- keyAttrs.recycle();
- }
- XmlParseUtils.checkEndTag(TAG_KEY_STYLE, parser);
- }
-
- private void startKeyboard() {
- mCurrentY += mParams.mTopPadding;
- mTopEdge = true;
- }
-
- private void startRow(Row row) {
- addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
- mCurrentRow = row;
- mLeftEdge = true;
- mRightEdgeKey = null;
- }
-
- private void endRow(Row row) {
- if (mCurrentRow == null) {
- throw new InflateException("orphan end row tag");
- }
- if (mRightEdgeKey != null) {
- mRightEdgeKey.markAsRightEdge(mParams);
- mRightEdgeKey = null;
- }
- addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
- mCurrentY += row.mRowHeight;
- mCurrentRow = null;
- mTopEdge = false;
- }
-
- private void endKey(Key key) {
- mParams.onAddKey(key);
- if (mLeftEdge) {
- key.markAsLeftEdge(mParams);
- mLeftEdge = false;
- }
- if (mTopEdge) {
- key.markAsTopEdge(mParams);
- }
- mRightEdgeKey = key;
- }
-
- private void endKeyboard() {
- // nothing to do here.
- }
-
- private void addEdgeSpace(float width, Row row) {
- row.advanceXPos(width);
- mLeftEdge = false;
- mRightEdgeKey = null;
- }
-
- public static float getDimensionOrFraction(TypedArray a, int index, int base,
- float defValue) {
- final TypedValue value = a.peekValue(index);
- if (value == null) {
- return defValue;
- }
- if (isFractionValue(value)) {
- return a.getFraction(index, base, base, defValue);
- } else if (isDimensionValue(value)) {
- return a.getDimension(index, defValue);
- }
- return defValue;
- }
-
- public static int getEnumValue(TypedArray a, int index, int defValue) {
- final TypedValue value = a.peekValue(index);
- if (value == null) {
- return defValue;
- }
- if (isIntegerValue(value)) {
- return a.getInt(index, defValue);
- }
- return defValue;
- }
-
- private static boolean isFractionValue(TypedValue v) {
- return v.type == TypedValue.TYPE_FRACTION;
- }
-
- private static boolean isDimensionValue(TypedValue v) {
- return v.type == TypedValue.TYPE_DIMENSION;
- }
-
- private static boolean isIntegerValue(TypedValue v) {
- return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT;
- }
-
- private static boolean isStringValue(TypedValue v) {
- return v.type == TypedValue.TYPE_STRING;
- }
-
- private static String textAttr(String value, String name) {
- return value != null ? String.format(" %s=%s", name, value) : "";
- }
-
- private static String booleanAttr(TypedArray a, int index, String name) {
- return a.hasValue(index)
- ? String.format(" %s=%s", name, a.getBoolean(index, false)) : "";
- }
- }
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 76ac3de22..aaccf63ba 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -35,7 +35,9 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
-import com.android.inputmethod.keyboard.KeyboardLayoutSet.Params.ElementParams;
+import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
+import com.android.inputmethod.keyboard.internal.KeyboardParams;
+import com.android.inputmethod.keyboard.internal.KeysCache;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.InputAttributes;
import com.android.inputmethod.latin.InputTypeUtils;
@@ -78,31 +80,19 @@ public class KeyboardLayoutSet {
public static class KeyboardLayoutSetException extends RuntimeException {
public final KeyboardId mKeyboardId;
- public KeyboardLayoutSetException(Throwable cause, KeyboardId keyboardId) {
+ public KeyboardLayoutSetException(final Throwable cause, final KeyboardId keyboardId) {
super(cause);
mKeyboardId = keyboardId;
}
}
- public static class KeysCache {
- private final HashMap<Key, Key> mMap = CollectionUtils.newHashMap();
-
- public void clear() {
- mMap.clear();
- }
-
- public Key get(Key key) {
- final Key existingKey = mMap.get(key);
- if (existingKey != null) {
- // Reuse the existing element that equals to "key" without adding "key" to the map.
- return existingKey;
- }
- mMap.put(key, key);
- return key;
- }
+ private static class ElementParams {
+ int mKeyboardXmlId;
+ boolean mProximityCharsCorrectionEnabled;
+ public ElementParams() {}
}
- static class Params {
+ private static class Params {
String mKeyboardLayoutSetName;
int mMode;
EditorInfo mEditorInfo;
@@ -118,11 +108,7 @@ public class KeyboardLayoutSet {
// Sparse array of KeyboardLayoutSet element parameters indexed by element's id.
final SparseArray<ElementParams> mKeyboardLayoutSetElementIdToParamsMap =
CollectionUtils.newSparseArray();
-
- static class ElementParams {
- int mKeyboardXmlId;
- boolean mProximityCharsCorrectionEnabled;
- }
+ public Params() {}
}
public static void clearKeyboardCache() {
@@ -130,12 +116,12 @@ public class KeyboardLayoutSet {
sKeysCache.clear();
}
- private KeyboardLayoutSet(Context context, Params params) {
+ KeyboardLayoutSet(final Context context, final Params params) {
mContext = context;
mParams = params;
}
- public Keyboard getKeyboard(int baseKeyboardLayoutSetElementId) {
+ public Keyboard getKeyboard(final int baseKeyboardLayoutSetElementId) {
final int keyboardLayoutSetElementId;
switch (mParams.mMode) {
case KeyboardId.MODE_PHONE:
@@ -170,12 +156,12 @@ public class KeyboardLayoutSet {
}
}
- private Keyboard getKeyboard(ElementParams elementParams, final KeyboardId id) {
+ private Keyboard getKeyboard(final ElementParams elementParams, final KeyboardId id) {
final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
Keyboard keyboard = (ref == null) ? null : ref.get();
if (keyboard == null) {
- final Keyboard.Builder<Keyboard.Params> builder =
- new Keyboard.Builder<Keyboard.Params>(mContext, new Keyboard.Params());
+ final KeyboardBuilder<KeyboardParams> builder =
+ new KeyboardBuilder<KeyboardParams>(mContext, new KeyboardParams());
if (id.isAlphabetKeyboard()) {
builder.setAutoGenerate(sKeysCache);
}
@@ -202,7 +188,7 @@ public class KeyboardLayoutSet {
// KeyboardLayoutSet element id that is a key in keyboard_set.xml. Also that file specifies
// which XML layout should be used for each keyboard. The KeyboardId is an internal key for
// Keyboard object.
- private KeyboardId getKeyboardId(int keyboardLayoutSetElementId) {
+ private KeyboardId getKeyboardId(final int keyboardLayoutSetElementId) {
final Params params = mParams;
final boolean isSymbols = (keyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS
|| keyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED);
@@ -225,7 +211,7 @@ public class KeyboardLayoutSet {
private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo();
- public Builder(Context context, EditorInfo editorInfo) {
+ public Builder(final Context context, final EditorInfo editorInfo) {
mContext = context;
mPackageName = context.getPackageName();
mResources = context.getResources();
@@ -238,7 +224,8 @@ public class KeyboardLayoutSet {
mPackageName, NO_SETTINGS_KEY, mEditorInfo);
}
- public Builder setScreenGeometry(int deviceFormFactor, int orientation, int widthPixels) {
+ public Builder setScreenGeometry(final int deviceFormFactor, final int orientation,
+ final int widthPixels) {
final Params params = mParams;
params.mDeviceFormFactor = deviceFormFactor;
params.mOrientation = orientation;
@@ -246,7 +233,7 @@ public class KeyboardLayoutSet {
return this;
}
- public Builder setSubtype(InputMethodSubtype subtype) {
+ public Builder setSubtype(final InputMethodSubtype subtype) {
final boolean asciiCapable = subtype.containsExtraValueKey(ASCII_CAPABLE);
@SuppressWarnings("deprecation")
final boolean deprecatedForceAscii = InputAttributes.inPrivateImeOptions(
@@ -263,8 +250,8 @@ public class KeyboardLayoutSet {
return this;
}
- public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain,
- boolean languageSwitchKeyEnabled) {
+ public Builder setOptions(final boolean voiceKeyEnabled, final boolean voiceKeyOnMain,
+ final boolean languageSwitchKeyEnabled) {
@SuppressWarnings("deprecation")
final boolean deprecatedNoMicrophone = InputAttributes.inPrivateImeOptions(
null, NO_MICROPHONE_COMPAT, mEditorInfo);
@@ -277,7 +264,7 @@ public class KeyboardLayoutSet {
return this;
}
- public void setTouchPositionCorrectionEnabled(boolean enabled) {
+ public void setTouchPositionCorrectionEnabled(final boolean enabled) {
mParams.mTouchPositionCorrectionEnabled = enabled;
}
@@ -298,7 +285,7 @@ public class KeyboardLayoutSet {
return new KeyboardLayoutSet(mContext, mParams);
}
- private void parseKeyboardLayoutSet(Resources res, int resId)
+ private void parseKeyboardLayoutSet(final Resources res, final int resId)
throws XmlPullParserException, IOException {
final XmlResourceParser parser = res.getXml(resId);
try {
@@ -318,7 +305,7 @@ public class KeyboardLayoutSet {
}
}
- private void parseKeyboardLayoutSetContent(XmlPullParser parser)
+ private void parseKeyboardLayoutSetContent(final XmlPullParser parser)
throws XmlPullParserException, IOException {
int event;
while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -340,7 +327,7 @@ public class KeyboardLayoutSet {
}
}
- private void parseKeyboardLayoutSetElement(XmlPullParser parser)
+ private void parseKeyboardLayoutSetElement(final XmlPullParser parser)
throws XmlPullParserException, IOException {
final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.KeyboardLayoutSet_Element);
@@ -367,7 +354,7 @@ public class KeyboardLayoutSet {
}
}
- private static int getKeyboardMode(EditorInfo editorInfo) {
+ private static int getKeyboardMode(final EditorInfo editorInfo) {
if (editorInfo == null)
return KeyboardId.MODE_TEXT;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index a4797095f..1e5ca9bf9 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -38,6 +38,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.android.inputmethod.keyboard.internal.KeyDrawParams;
+import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams;
import com.android.inputmethod.keyboard.internal.PreviewPlacerView;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.Constants;
@@ -84,8 +86,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// Miscellaneous constants
private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable };
- private static final float UNDEFINED_RATIO = -1.0f;
- private static final int UNDEFINED_DIMENSION = -1;
// XML attributes
protected final float mVerticalCorrection;
@@ -180,187 +180,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
}
- // Move this class to internal package
- protected static class KeyDrawParams {
- // XML attributes
- public final int mKeyTextColor;
- public final int mKeyTextInactivatedColor;
- public final float mKeyLabelHorizontalPadding;
- public final float mKeyHintLetterPadding;
- public final float mKeyPopupHintLetterPadding;
- public final float mKeyShiftedLetterHintPadding;
- public final int mShadowColor;
- public final float mShadowRadius;
- public final Drawable mKeyBackground;
- public final int mKeyHintLetterColor;
- public final int mKeyHintLabelColor;
- public final int mKeyShiftedLetterHintInactivatedColor;
- public final int mKeyShiftedLetterHintActivatedColor;
-
- private final Typeface mKeyTypefaceFromKeyboardView;
- private final float mKeyLetterRatio;
- private final float mKeyLargeLetterRatio;
- private final float mKeyLabelRatio;
- private final float mKeyLargeLabelRatio;
- private final float mKeyHintLetterRatio;
- private final float mKeyShiftedLetterHintRatio;
- private final float mKeyHintLabelRatio;
-
- public final Rect mPadding = new Rect();
- public Typeface mKeyTypeface;
- public int mKeyLetterSize;
- public int mKeyLargeLetterSize;
- public int mKeyLabelSize;
- public int mKeyLargeLabelSize;
- public int mKeyHintLetterSize;
- public int mKeyShiftedLetterHintSize;
- public int mKeyHintLabelSize;
- public int mAnimAlpha;
-
- public KeyDrawParams(final TypedArray a) {
- mKeyBackground = a.getDrawable(R.styleable.KeyboardView_keyBackground);
- if (!isValidFraction(mKeyLetterRatio = getFraction(a,
- R.styleable.KeyboardView_keyLetterSize))) {
- mKeyLetterSize = getDimensionPixelSize(a, R.styleable.KeyboardView_keyLetterSize);
- }
- if (!isValidFraction(mKeyLabelRatio = getFraction(a,
- R.styleable.KeyboardView_keyLabelSize))) {
- mKeyLabelSize = getDimensionPixelSize(a, R.styleable.KeyboardView_keyLabelSize);
- }
- mKeyLargeLabelRatio = getFraction(a, R.styleable.KeyboardView_keyLargeLabelRatio);
- mKeyLargeLetterRatio = getFraction(a, R.styleable.KeyboardView_keyLargeLetterRatio);
- mKeyHintLetterRatio = getFraction(a, R.styleable.KeyboardView_keyHintLetterRatio);
- mKeyShiftedLetterHintRatio = getFraction(a,
- R.styleable.KeyboardView_keyShiftedLetterHintRatio);
- mKeyHintLabelRatio = getFraction(a, R.styleable.KeyboardView_keyHintLabelRatio);
- mKeyLabelHorizontalPadding = a.getDimension(
- R.styleable.KeyboardView_keyLabelHorizontalPadding, 0);
- mKeyHintLetterPadding = a.getDimension(
- R.styleable.KeyboardView_keyHintLetterPadding, 0);
- mKeyPopupHintLetterPadding = a.getDimension(
- R.styleable.KeyboardView_keyPopupHintLetterPadding, 0);
- mKeyShiftedLetterHintPadding = a.getDimension(
- R.styleable.KeyboardView_keyShiftedLetterHintPadding, 0);
- mKeyTextColor = a.getColor(R.styleable.KeyboardView_keyTextColor, 0xFF000000);
- mKeyTextInactivatedColor = a.getColor(
- R.styleable.KeyboardView_keyTextInactivatedColor, 0xFF000000);
- mKeyHintLetterColor = a.getColor(R.styleable.KeyboardView_keyHintLetterColor, 0);
- mKeyHintLabelColor = a.getColor(R.styleable.KeyboardView_keyHintLabelColor, 0);
- mKeyShiftedLetterHintInactivatedColor = a.getColor(
- R.styleable.KeyboardView_keyShiftedLetterHintInactivatedColor, 0);
- mKeyShiftedLetterHintActivatedColor = a.getColor(
- R.styleable.KeyboardView_keyShiftedLetterHintActivatedColor, 0);
- mKeyTypefaceFromKeyboardView = Typeface.defaultFromStyle(
- a.getInt(R.styleable.KeyboardView_keyTypeface, Typeface.NORMAL));
- mKeyTypeface = mKeyTypefaceFromKeyboardView;
- mShadowColor = a.getColor(R.styleable.KeyboardView_shadowColor, 0);
- mShadowRadius = a.getFloat(R.styleable.KeyboardView_shadowRadius, 0f);
-
- mKeyBackground.getPadding(mPadding);
- }
-
- public void updateParams(final Keyboard keyboard) {
- mKeyTypeface = (keyboard.mKeyTypeface != null)
- ? keyboard.mKeyTypeface : mKeyTypefaceFromKeyboardView;
- final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
- if (isValidFraction(mKeyLetterRatio)) {
- mKeyLetterSize = (int)(keyHeight * mKeyLetterRatio);
- }
- if (isValidFraction(mKeyLabelRatio)) {
- mKeyLabelSize = (int)(keyHeight * mKeyLabelRatio);
- }
- mKeyLargeLabelSize = (int)(keyHeight * mKeyLargeLabelRatio);
- mKeyLargeLetterSize = (int)(keyHeight * mKeyLargeLetterRatio);
- mKeyHintLetterSize = (int)(keyHeight * mKeyHintLetterRatio);
- mKeyShiftedLetterHintSize = (int)(keyHeight * mKeyShiftedLetterHintRatio);
- mKeyHintLabelSize = (int)(keyHeight * mKeyHintLabelRatio);
- }
-
- public void blendAlpha(final Paint paint) {
- final int color = paint.getColor();
- paint.setARGB((paint.getAlpha() * mAnimAlpha) / Constants.Color.ALPHA_OPAQUE,
- Color.red(color), Color.green(color), Color.blue(color));
- }
- }
-
- // TODO: Move this class to internal package.
- /* package */ static class KeyPreviewDrawParams {
- // XML attributes.
- public final Drawable mPreviewBackground;
- public final Drawable mPreviewLeftBackground;
- public final Drawable mPreviewRightBackground;
- public final int mPreviewTextColor;
- public final int mPreviewOffset;
- public final int mPreviewHeight;
- public final int mLingerTimeout;
-
- private final float mPreviewTextRatio;
-
- // The graphical geometry of the key preview.
- // <-width->
- // +-------+ ^
- // | | |
- // |preview| height (visible)
- // | | |
- // + + ^ v
- // \ / |offset
- // +-\ /-+ v
- // | +-+ |
- // |parent |
- // | key|
- // +-------+
- // The background of a {@link TextView} being used for a key preview may have invisible
- // paddings. To align the more keys keyboard panel's visible part with the visible part of
- // the background, we need to record the width and height of key preview that don't include
- // invisible paddings.
- public int mPreviewVisibleWidth;
- public int mPreviewVisibleHeight;
- // The key preview may have an arbitrary offset and its background that may have a bottom
- // padding. To align the more keys keyboard and the key preview we also need to record the
- // offset between the top edge of parent key and the bottom of the visible part of key
- // preview background.
- public int mPreviewVisibleOffset;
-
- public Typeface mKeyTypeface;
- public int mPreviewTextSize;
- public int mKeyLetterSize;
- public final int[] mCoordinates = new int[2];
-
- private static final int PREVIEW_ALPHA = 240;
-
- public KeyPreviewDrawParams(final TypedArray a) {
- mPreviewBackground = a.getDrawable(R.styleable.KeyboardView_keyPreviewBackground);
- mPreviewLeftBackground = a.getDrawable(
- R.styleable.KeyboardView_keyPreviewLeftBackground);
- mPreviewRightBackground = a.getDrawable(
- R.styleable.KeyboardView_keyPreviewRightBackground);
- setAlpha(mPreviewBackground, PREVIEW_ALPHA);
- setAlpha(mPreviewLeftBackground, PREVIEW_ALPHA);
- setAlpha(mPreviewRightBackground, PREVIEW_ALPHA);
- mPreviewOffset = a.getDimensionPixelOffset(
- R.styleable.KeyboardView_keyPreviewOffset, 0);
- mPreviewHeight = a.getDimensionPixelSize(
- R.styleable.KeyboardView_keyPreviewHeight, 80);
- mPreviewTextRatio = getFraction(a, R.styleable.KeyboardView_keyPreviewTextRatio);
- mPreviewTextColor = a.getColor(R.styleable.KeyboardView_keyPreviewTextColor, 0);
- mLingerTimeout = a.getInt(R.styleable.KeyboardView_keyPreviewLingerTimeout, 0);
- }
-
- public void updateParams(final Keyboard keyboard, final KeyDrawParams keyDrawParams) {
- final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
- if (isValidFraction(mPreviewTextRatio)) {
- mPreviewTextSize = (int)(keyHeight * mPreviewTextRatio);
- }
- mKeyLetterSize = keyDrawParams.mKeyLetterSize;
- mKeyTypeface = keyDrawParams.mKeyTypeface;
- }
-
- private static void setAlpha(final Drawable drawable, final int alpha) {
- if (drawable == null) return;
- drawable.setAlpha(alpha);
- }
- }
-
public KeyboardView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.keyboardViewStyle);
}
@@ -368,45 +187,31 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
public KeyboardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- final TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
- mKeyDrawParams = new KeyDrawParams(a);
- mKeyPreviewDrawParams = new KeyPreviewDrawParams(a);
+ final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs,
+ R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
+ final TypedArray keyAttr = context.obtainStyledAttributes(attrs,
+ R.styleable.Keyboard_Key, defStyle, R.style.KeyboardView);
+ mKeyDrawParams = new KeyDrawParams(keyboardViewAttr, keyAttr);
+ mKeyPreviewDrawParams = new KeyPreviewDrawParams(keyboardViewAttr, keyAttr);
mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout;
- mKeyPreviewLayoutId = a.getResourceId(R.styleable.KeyboardView_keyPreviewLayout, 0);
+ mKeyPreviewLayoutId = keyboardViewAttr.getResourceId(
+ R.styleable.KeyboardView_keyPreviewLayout, 0);
if (mKeyPreviewLayoutId == 0) {
mShowKeyPreviewPopup = false;
}
- mVerticalCorrection = a.getDimensionPixelOffset(
+ mVerticalCorrection = keyboardViewAttr.getDimensionPixelOffset(
R.styleable.KeyboardView_verticalCorrection, 0);
- mMoreKeysLayout = a.getResourceId(R.styleable.KeyboardView_moreKeysLayout, 0);
- mBackgroundDimAlpha = a.getInt(R.styleable.KeyboardView_backgroundDimAlpha, 0);
- a.recycle();
+ mMoreKeysLayout = keyboardViewAttr.getResourceId(
+ R.styleable.KeyboardView_moreKeysLayout, 0);
+ mBackgroundDimAlpha = keyboardViewAttr.getInt(
+ R.styleable.KeyboardView_backgroundDimAlpha, 0);
+ keyboardViewAttr.recycle();
+ keyAttr.recycle();
mPreviewPlacerView = new PreviewPlacerView(context, attrs);
mPaint.setAntiAlias(true);
}
- static boolean isValidFraction(final float fraction) {
- return fraction >= 0.0f;
- }
-
- static float getFraction(final TypedArray a, final int index) {
- final TypedValue value = a.peekValue(index);
- if (value == null || value.type != TypedValue.TYPE_FRACTION) {
- return UNDEFINED_RATIO;
- }
- return a.getFraction(index, 1, 1, UNDEFINED_RATIO);
- }
-
- public static int getDimensionPixelSize(final TypedArray a, final int index) {
- final TypedValue value = a.peekValue(index);
- if (value == null || value.type != TypedValue.TYPE_DIMENSION) {
- return UNDEFINED_DIMENSION;
- }
- return a.getDimensionPixelSize(index, UNDEFINED_DIMENSION);
- }
-
/**
* Attaches a keyboard to this view. The keyboard can be switched at any time and the
* view will re-layout itself to accommodate the keyboard.
@@ -598,7 +403,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
}
private void onDrawKey(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
- final int keyDrawX = key.mX + key.mVisualInsetsLeft + getPaddingLeft();
+ final int keyDrawX = key.getDrawX() + getPaddingLeft();
final int keyDrawY = key.mY + getPaddingTop();
canvas.translate(keyDrawX, keyDrawY);
@@ -613,8 +418,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// Draw key background.
protected void onDrawKeyBackground(Key key, Canvas canvas, KeyDrawParams params) {
- final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight
- + params.mPadding.left + params.mPadding.right;
+ final int bgWidth = key.getDrawWidth() + params.mPadding.left + params.mPadding.right;
final int bgHeight = key.mHeight + params.mPadding.top + params.mPadding.bottom;
final int bgX = -params.mPadding.left;
final int bgY = -params.mPadding.top;
@@ -635,7 +439,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// Draw key top visuals.
protected void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
- final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
+ final int keyWidth = key.getDrawWidth();
final int keyHeight = key.mHeight;
final float centerX = keyWidth * 0.5f;
final float centerY = keyHeight * 0.5f;
@@ -696,7 +500,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
? params.mKeyTextInactivatedColor : params.mKeyTextColor);
if (key.isEnabled()) {
// Set a drop shadow for the text
- paint.setShadowLayer(params.mShadowRadius, 0, 0, params.mShadowColor);
+ paint.setShadowLayer(params.mKeyTextShadowRadius, 0, 0, params.mKeyTextShadowColor);
} else {
// Make label invisible
paint.setColor(Color.TRANSPARENT);
@@ -811,7 +615,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// Draw popup hint "..." at the bottom right corner of the key.
protected void drawKeyPopupHint(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
- final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
+ final int keyWidth = key.getDrawWidth();
final int keyHeight = key.mHeight;
paint.setTypeface(params.mKeyTypeface);
@@ -1002,7 +806,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
@SuppressWarnings("deprecation") // setBackgroundDrawable is replaced by setBackground in API16
@Override
public void showKeyPreview(PointerTracker tracker) {
- if (!mShowKeyPreviewPopup) return;
+ final KeyPreviewDrawParams params = mKeyPreviewDrawParams;
+ if (!mShowKeyPreviewPopup) {
+ params.mPreviewVisibleOffset = -mKeyboard.mVerticalGap;
+ return;
+ }
final TextView previewText = getKeyPreviewText(tracker.mPointerId);
// If the key preview has no parent view yet, add it to the ViewGroup which can place
@@ -1019,7 +827,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
if (key == null)
return;
- final KeyPreviewDrawParams params = mKeyPreviewDrawParams;
final String label = key.isShiftedLetterActivated() ? key.mHintLabel : key.mLabel;
// What we show as preview should match what we show on a key top in onDraw().
if (label != null) {
@@ -1042,7 +849,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
previewText.measure(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
+ final int keyDrawWidth = key.getDrawWidth();
final int previewWidth = previewText.getMeasuredWidth();
final int previewHeight = params.mPreviewHeight;
// The width and height of visible part of the key preview background. The content marker
@@ -1058,8 +865,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
// The key preview is horizontally aligned with the center of the visible part of the
// parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and
// the left/right background is used if such background is specified.
- int previewX = key.mX + key.mVisualInsetsLeft - (previewWidth - keyDrawWidth) / 2
- + params.mCoordinates[0];
+ int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 + params.mCoordinates[0];
if (previewX < 0) {
previewX = 0;
if (params.mPreviewLeftBackground != null) {
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 358061b47..2da2f6dc6 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -43,6 +43,7 @@ import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
+import com.android.inputmethod.keyboard.internal.KeyDrawParams;
import com.android.inputmethod.keyboard.internal.SuddenJumpingTouchEventHandler;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.LatinIME;
@@ -334,7 +335,7 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
final Resources res = getResources();
final boolean needsPhantomSuddenMoveEventHack = Boolean.parseBoolean(
- ResourceUtils.getDeviceOverrideValue(res,
+ ResourceUtils.getDeviceOverrideValue(res,
R.array.phantom_sudden_move_event_device_list, "false"));
PointerTracker.init(mHasDistinctMultitouch, needsPhantomSuddenMoveEventHack);
@@ -618,9 +619,9 @@ public class MainKeyboardView extends KeyboardView implements PointerTracker.Key
// The more keys keyboard is usually vertically aligned with the top edge of the parent key
// (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically
// aligned with the bottom edge of the visible part of the key preview.
- final int pointY = parentKey.mY + (keyPreviewEnabled
- ? mKeyPreviewDrawParams.mPreviewVisibleOffset
- : -parentKey.mVerticalGap);
+ // {@code mPreviewVisibleOffset} has been set appropriately in
+ // {@link KeyboardView#showKeyPreview(PointerTracker)}.
+ final int pointY = parentKey.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset;
moreKeysPanel.showMoreKeysPanel(
this, this, pointX, pointY, mMoreKeysWindow, mKeyboardActionListener);
final int translatedX = moreKeysPanel.translateX(tracker.getLastX());
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index a3741a2d8..51b157c28 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -20,15 +20,17 @@ import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.view.View;
-import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
+import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.keyboard.internal.KeyboardParams;
+import com.android.inputmethod.keyboard.internal.MoreKeySpec;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StringUtils;
public class MoreKeysKeyboard extends Keyboard {
private final int mDefaultKeyCoordX;
- MoreKeysKeyboard(Builder.MoreKeysKeyboardParams params) {
+ MoreKeysKeyboard(final MoreKeysKeyboardParams params) {
super(params);
mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2;
}
@@ -37,228 +39,231 @@ public class MoreKeysKeyboard extends Keyboard {
return mDefaultKeyCoordX;
}
- public static class Builder extends Keyboard.Builder<Builder.MoreKeysKeyboardParams> {
- private final Key mParentKey;
- private final Drawable mDivider;
-
- private static final float LABEL_PADDING_RATIO = 0.2f;
- private static final float DIVIDER_RATIO = 0.2f;
+ /* package for test */
+ static class MoreKeysKeyboardParams extends KeyboardParams {
+ public boolean mIsFixedOrder;
+ /* package */int mTopRowAdjustment;
+ public int mNumRows;
+ public int mNumColumns;
+ public int mTopKeys;
+ public int mLeftKeys;
+ public int mRightKeys; // includes default key.
+ public int mDividerWidth;
+ public int mColumnWidth;
+
+ public MoreKeysKeyboardParams() {
+ super();
+ }
- public static class MoreKeysKeyboardParams extends Keyboard.Params {
- public boolean mIsFixedOrder;
- /* package */int mTopRowAdjustment;
- public int mNumRows;
- public int mNumColumns;
- public int mTopKeys;
- public int mLeftKeys;
- public int mRightKeys; // includes default key.
- public int mDividerWidth;
- public int mColumnWidth;
-
- public MoreKeysKeyboardParams() {
- super();
+ /**
+ * Set keyboard parameters of more keys 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.
+ * @param isFixedColumnOrder if true, more keys should be laid out in fixed order.
+ * @param dividerWidth width of divider, zero for no dividers.
+ */
+ public void setParameters(final int numKeys, final int maxColumns, final int keyWidth,
+ final int rowHeight, final int coordXInParent, final int parentKeyboardWidth,
+ final boolean isFixedColumnOrder, final int dividerWidth) {
+ mIsFixedOrder = isFixedColumnOrder;
+ if (parentKeyboardWidth / keyWidth < maxColumns) {
+ throw new IllegalArgumentException(
+ "Keyboard is too small to hold more keys keyboard: "
+ + parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
}
-
- /**
- * Set keyboard parameters of more keys 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.
- * @param isFixedColumnOrder if true, more keys should be laid out in fixed order.
- * @param dividerWidth width of divider, zero for no dividers.
- */
- public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight,
- int coordXInParent, int parentKeyboardWidth, boolean isFixedColumnOrder,
- int dividerWidth) {
- mIsFixedOrder = isFixedColumnOrder;
- if (parentKeyboardWidth / keyWidth < maxColumns) {
- throw new IllegalArgumentException(
- "Keyboard is too small to hold more keys keyboard: "
- + parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
- }
- mDefaultKeyWidth = keyWidth;
- mDefaultRowHeight = rowHeight;
-
- final int numRows = (numKeys + maxColumns - 1) / maxColumns;
- mNumRows = numRows;
- final int numColumns = mIsFixedOrder ? Math.min(numKeys, maxColumns)
- : getOptimizedColumns(numKeys, maxColumns);
- mNumColumns = numColumns;
- final int topKeys = numKeys % numColumns;
- mTopKeys = topKeys == 0 ? numColumns : topKeys;
-
- final int numLeftKeys = (numColumns - 1) / 2;
- final int numRightKeys = numColumns - numLeftKeys; // including default key.
- // Maximum number of keys we can layout both side of the parent key
- final int maxLeftKeys = coordXInParent / keyWidth;
- final int maxRightKeys = (parentKeyboardWidth - coordXInParent) / keyWidth;
- int leftKeys, rightKeys;
- if (numLeftKeys > maxLeftKeys) {
- leftKeys = maxLeftKeys;
- rightKeys = numColumns - leftKeys;
- } else if (numRightKeys > maxRightKeys + 1) {
- rightKeys = maxRightKeys + 1; // include default key
- leftKeys = numColumns - rightKeys;
- } else {
- leftKeys = numLeftKeys;
- rightKeys = numRightKeys;
- }
- // If the left keys fill the left side of the parent key, entire more keys keyboard
- // should be shifted to the right unless the parent key is on the left edge.
- if (maxLeftKeys == leftKeys && leftKeys > 0) {
- leftKeys--;
- rightKeys++;
- }
- // If the right keys fill the right side of the parent key, entire more keys
- // should be shifted to the left unless the parent key is on the right edge.
- if (maxRightKeys == rightKeys - 1 && rightKeys > 1) {
- leftKeys++;
- rightKeys--;
- }
- mLeftKeys = leftKeys;
- mRightKeys = rightKeys;
-
- // Adjustment of the top row.
- mTopRowAdjustment = mIsFixedOrder ? getFixedOrderTopRowAdjustment()
- : getAutoOrderTopRowAdjustment();
- mDividerWidth = dividerWidth;
- mColumnWidth = mDefaultKeyWidth + mDividerWidth;
- mBaseWidth = mOccupiedWidth = mNumColumns * mColumnWidth - mDividerWidth;
- // Need to subtract the bottom row's gutter only.
- mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
- + mTopPadding + mBottomPadding;
+ mDefaultKeyWidth = keyWidth;
+ mDefaultRowHeight = rowHeight;
+
+ final int numRows = (numKeys + maxColumns - 1) / maxColumns;
+ mNumRows = numRows;
+ final int numColumns = mIsFixedOrder ? Math.min(numKeys, maxColumns)
+ : getOptimizedColumns(numKeys, maxColumns);
+ mNumColumns = numColumns;
+ final int topKeys = numKeys % numColumns;
+ mTopKeys = topKeys == 0 ? numColumns : topKeys;
+
+ final int numLeftKeys = (numColumns - 1) / 2;
+ final int numRightKeys = numColumns - numLeftKeys; // including default key.
+ // Maximum number of keys we can layout both side of the parent key
+ final int maxLeftKeys = coordXInParent / keyWidth;
+ final int maxRightKeys = (parentKeyboardWidth - coordXInParent) / keyWidth;
+ int leftKeys, rightKeys;
+ if (numLeftKeys > maxLeftKeys) {
+ leftKeys = maxLeftKeys;
+ rightKeys = numColumns - leftKeys;
+ } else if (numRightKeys > maxRightKeys + 1) {
+ rightKeys = maxRightKeys + 1; // include default key
+ leftKeys = numColumns - rightKeys;
+ } else {
+ leftKeys = numLeftKeys;
+ rightKeys = numRightKeys;
}
-
- private int getFixedOrderTopRowAdjustment() {
- if (mNumRows == 1 || mTopKeys % 2 == 1 || mTopKeys == mNumColumns
- || mLeftKeys == 0 || mRightKeys == 1) {
- return 0;
- }
- return -1;
+ // If the left keys fill the left side of the parent key, entire more keys keyboard
+ // should be shifted to the right unless the parent key is on the left edge.
+ if (maxLeftKeys == leftKeys && leftKeys > 0) {
+ leftKeys--;
+ rightKeys++;
}
-
- private int getAutoOrderTopRowAdjustment() {
- if (mNumRows == 1 || mTopKeys == 1 || mNumColumns % 2 == mTopKeys % 2
- || mLeftKeys == 0 || mRightKeys == 1) {
- return 0;
- }
- return -1;
+ // If the right keys fill the right side of the parent key, entire more keys
+ // should be shifted to the left unless the parent key is on the right edge.
+ if (maxRightKeys == rightKeys - 1 && rightKeys > 1) {
+ leftKeys++;
+ rightKeys--;
}
+ mLeftKeys = leftKeys;
+ mRightKeys = rightKeys;
+
+ // Adjustment of the top row.
+ mTopRowAdjustment = mIsFixedOrder ? getFixedOrderTopRowAdjustment()
+ : getAutoOrderTopRowAdjustment();
+ mDividerWidth = dividerWidth;
+ mColumnWidth = mDefaultKeyWidth + mDividerWidth;
+ mBaseWidth = mOccupiedWidth = mNumColumns * mColumnWidth - mDividerWidth;
+ // Need to subtract the bottom row's gutter only.
+ mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
+ + mTopPadding + mBottomPadding;
+ }
- // Return key position according to column count (0 is default).
- /* package */int getColumnPos(int n) {
- return mIsFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
+ private int getFixedOrderTopRowAdjustment() {
+ if (mNumRows == 1 || mTopKeys % 2 == 1 || mTopKeys == mNumColumns
+ || mLeftKeys == 0 || mRightKeys == 1) {
+ return 0;
}
+ return -1;
+ }
- private int getFixedOrderColumnPos(int n) {
- final int col = n % mNumColumns;
- final int row = n / mNumColumns;
- if (!isTopRow(row)) {
- return col - mLeftKeys;
- }
- final int rightSideKeys = mTopKeys / 2;
- final int leftSideKeys = mTopKeys - (rightSideKeys + 1);
- final int pos = col - leftSideKeys;
- final int numLeftKeys = mLeftKeys + mTopRowAdjustment;
- final int numRightKeys = mRightKeys - 1;
- if (numRightKeys >= rightSideKeys && numLeftKeys >= leftSideKeys) {
- return pos;
- } else if (numRightKeys < rightSideKeys) {
- return pos - (rightSideKeys - numRightKeys);
- } else { // numLeftKeys < leftSideKeys
- return pos + (leftSideKeys - numLeftKeys);
- }
+ private int getAutoOrderTopRowAdjustment() {
+ if (mNumRows == 1 || mTopKeys == 1 || mNumColumns % 2 == mTopKeys % 2
+ || mLeftKeys == 0 || mRightKeys == 1) {
+ return 0;
}
+ return -1;
+ }
- private int getAutomaticColumnPos(int n) {
- final int col = n % mNumColumns;
- final int row = n / mNumColumns;
- int leftKeys = mLeftKeys;
- if (isTopRow(row)) {
- leftKeys += mTopRowAdjustment;
- }
- if (col == 0) {
- // default position.
- return 0;
- }
+ // Return key position according to column count (0 is default).
+ /* package */int getColumnPos(final int n) {
+ return mIsFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
+ }
- int pos = 0;
- int right = 1; // include default position key.
- int left = 0;
- int i = 0;
- while (true) {
- // Assign right key if available.
- if (right < mRightKeys) {
- pos = right;
- right++;
- i++;
- }
- if (i >= col)
- break;
- // Assign left key if available.
- if (left < leftKeys) {
- left++;
- pos = -left;
- i++;
- }
- if (i >= col)
- break;
- }
+ private int getFixedOrderColumnPos(final int n) {
+ final int col = n % mNumColumns;
+ final int row = n / mNumColumns;
+ if (!isTopRow(row)) {
+ return col - mLeftKeys;
+ }
+ final int rightSideKeys = mTopKeys / 2;
+ final int leftSideKeys = mTopKeys - (rightSideKeys + 1);
+ final int pos = col - leftSideKeys;
+ final int numLeftKeys = mLeftKeys + mTopRowAdjustment;
+ final int numRightKeys = mRightKeys - 1;
+ if (numRightKeys >= rightSideKeys && numLeftKeys >= leftSideKeys) {
return pos;
+ } else if (numRightKeys < rightSideKeys) {
+ return pos - (rightSideKeys - numRightKeys);
+ } else { // numLeftKeys < leftSideKeys
+ return pos + (leftSideKeys - numLeftKeys);
}
+ }
- private static int getTopRowEmptySlots(int numKeys, int numColumns) {
- final int remainings = numKeys % numColumns;
- return remainings == 0 ? 0 : numColumns - remainings;
+ private int getAutomaticColumnPos(final int n) {
+ final int col = n % mNumColumns;
+ final int row = n / mNumColumns;
+ int leftKeys = mLeftKeys;
+ if (isTopRow(row)) {
+ leftKeys += mTopRowAdjustment;
+ }
+ if (col == 0) {
+ // default position.
+ return 0;
}
- private int getOptimizedColumns(int numKeys, int maxColumns) {
- int numColumns = Math.min(numKeys, maxColumns);
- while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
- numColumns--;
+ int pos = 0;
+ int right = 1; // include default position key.
+ int left = 0;
+ int i = 0;
+ while (true) {
+ // Assign right key if available.
+ if (right < mRightKeys) {
+ pos = right;
+ right++;
+ i++;
}
- return numColumns;
+ if (i >= col)
+ break;
+ // Assign left key if available.
+ if (left < leftKeys) {
+ left++;
+ pos = -left;
+ i++;
+ }
+ if (i >= col)
+ break;
}
+ return pos;
+ }
- public int getDefaultKeyCoordX() {
- return mLeftKeys * mColumnWidth;
- }
+ private static int getTopRowEmptySlots(final int numKeys, final int numColumns) {
+ final int remainings = numKeys % numColumns;
+ return remainings == 0 ? 0 : numColumns - remainings;
+ }
- public int getX(int n, int row) {
- final int x = getColumnPos(n) * mColumnWidth + getDefaultKeyCoordX();
- if (isTopRow(row)) {
- return x + mTopRowAdjustment * (mColumnWidth / 2);
- }
- return x;
+ private int getOptimizedColumns(final int numKeys, final int maxColumns) {
+ int numColumns = Math.min(numKeys, maxColumns);
+ while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
+ numColumns--;
}
+ return numColumns;
+ }
- public int getY(int row) {
- return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding;
- }
+ public int getDefaultKeyCoordX() {
+ return mLeftKeys * mColumnWidth;
+ }
- public void markAsEdgeKey(Key key, int row) {
- if (row == 0)
- key.markAsTopEdge(this);
- if (isTopRow(row))
- key.markAsBottomEdge(this);
+ public int getX(final int n, final int row) {
+ final int x = getColumnPos(n) * mColumnWidth + getDefaultKeyCoordX();
+ if (isTopRow(row)) {
+ return x + mTopRowAdjustment * (mColumnWidth / 2);
}
+ return x;
+ }
- private boolean isTopRow(int rowCount) {
- return mNumRows > 1 && rowCount == mNumRows - 1;
- }
+ public int getY(final int row) {
+ return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding;
}
+ public void markAsEdgeKey(final Key key, final int row) {
+ if (row == 0)
+ key.markAsTopEdge(this);
+ if (isTopRow(row))
+ key.markAsBottomEdge(this);
+ }
+
+ private boolean isTopRow(final int rowCount) {
+ return mNumRows > 1 && rowCount == mNumRows - 1;
+ }
+ }
+
+ public static class Builder extends KeyboardBuilder<MoreKeysKeyboardParams> {
+ private final Key mParentKey;
+ private final Drawable mDivider;
+
+ private static final float LABEL_PADDING_RATIO = 0.2f;
+ private static final float DIVIDER_RATIO = 0.2f;
+
+
/**
* The builder of MoreKeysKeyboard.
* @param containerView the container of {@link MoreKeysKeyboardView}.
* @param parentKey the {@link Key} that invokes more keys keyboard.
* @param parentKeyboardView the {@link KeyboardView} that contains the parentKey.
*/
- public Builder(View containerView, Key parentKey, KeyboardView parentKeyboardView) {
+ public Builder(final View containerView, final Key parentKey,
+ final KeyboardView parentKeyboardView) {
super(containerView.getContext(), new MoreKeysKeyboardParams());
final Keyboard parentKeyboard = parentKeyboardView.getKeyboard();
load(parentKeyboard.mMoreKeysTemplate, parentKeyboard.mId);
@@ -300,7 +305,8 @@ public class MoreKeysKeyboard extends Keyboard {
dividerWidth);
}
- private static int getMaxKeyWidth(KeyboardView view, Key parentKey, int minKeyWidth) {
+ private static int getMaxKeyWidth(final KeyboardView view, final Key parentKey,
+ final int minKeyWidth) {
final int padding = (int)(view.getResources()
.getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding)
+ (parentKey.hasLabelsInMoreKeys() ? minKeyWidth * LABEL_PADDING_RATIO : 0));
@@ -322,24 +328,6 @@ public class MoreKeysKeyboard extends Keyboard {
return maxWidth;
}
- private static class MoreKeyDivider extends Key.Spacer {
- private final Drawable mIcon;
-
- public MoreKeyDivider(MoreKeysKeyboardParams params, Drawable icon, int x, int y) {
- super(params, x, y, params.mDividerWidth, params.mDefaultRowHeight);
- mIcon = icon;
- }
-
- @Override
- public Drawable getIcon(KeyboardIconsSet iconSet, int alpha) {
- // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
- // constructor.
- // TODO: Drawable itself should have an alpha value.
- mIcon.setAlpha(128);
- return mIcon;
- }
- }
-
@Override
public MoreKeysKeyboard build() {
final MoreKeysKeyboardParams params = mParams;
@@ -368,4 +356,23 @@ public class MoreKeysKeyboard extends Keyboard {
return new MoreKeysKeyboard(params);
}
}
+
+ private static class MoreKeyDivider extends Key.Spacer {
+ private final Drawable mIcon;
+
+ public MoreKeyDivider(final MoreKeysKeyboardParams params, final Drawable icon,
+ final int x, final int y) {
+ super(params, x, y, params.mDividerWidth, params.mDefaultRowHeight);
+ mIcon = icon;
+ }
+
+ @Override
+ public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
+ // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
+ // constructor.
+ // TODO: Drawable itself should have an alpha value.
+ mIcon.setAlpha(128);
+ return mIcon;
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index be101cfb0..5a79d508f 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -330,10 +330,10 @@ public class PointerTracker implements PointerTrackerQueue.Element {
final int y) {
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState();
- final int code = altersCode ? key.mAltCode : primaryCode;
+ final int code = altersCode ? key.getAltCode() : primaryCode;
if (DEBUG_LISTENER) {
- Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) + " text=" + key.mOutputText
- + " x=" + x + " y=" + y
+ Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code)
+ + " text=" + key.getOutputText() + " x=" + x + " y=" + y
+ " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode
+ " enabled=" + key.isEnabled());
}
@@ -347,7 +347,7 @@ public class PointerTracker implements PointerTrackerQueue.Element {
// Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state.
if (key.isEnabled() || altersCode) {
if (code == Keyboard.CODE_OUTPUT_TEXT) {
- mListener.onTextInput(key.mOutputText);
+ mListener.onTextInput(key.getOutputText());
} else if (code != Keyboard.CODE_UNSPECIFIED) {
mListener.onCodeInput(code, x, y);
}
@@ -440,13 +440,13 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
if (key.altCodeWhileTyping()) {
- final int altCode = key.mAltCode;
+ final int altCode = key.getAltCode();
final Key altKey = mKeyboard.getKey(altCode);
if (altKey != null) {
updateReleaseKeyGraphics(altKey);
}
for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) {
- if (k != key && k.mAltCode == altCode) {
+ if (k != key && k.getAltCode() == altCode) {
updateReleaseKeyGraphics(k);
}
}
@@ -479,13 +479,13 @@ public class PointerTracker implements PointerTrackerQueue.Element {
}
if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) {
- final int altCode = key.mAltCode;
+ final int altCode = key.getAltCode();
final Key altKey = mKeyboard.getKey(altCode);
if (altKey != null) {
updatePressKeyGraphics(altKey);
}
for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) {
- if (k != key && k.mAltCode == altCode) {
+ if (k != key && k.getAltCode() == altCode) {
updatePressKeyGraphics(k);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 71bf31faa..e1b082c16 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -19,7 +19,7 @@ package com.android.inputmethod.keyboard;
import android.graphics.Rect;
import android.text.TextUtils;
-import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection;
+import com.android.inputmethod.keyboard.internal.TouchPositionCorrection;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.JniUtils;
@@ -48,9 +48,10 @@ public class ProximityInfo {
private final Key[][] mGridNeighbors;
private final String mLocaleStr;
- ProximityInfo(String localeStr, int gridWidth, int gridHeight, int minWidth, int height,
- int mostCommonKeyWidth, int mostCommonKeyHeight, final Key[] keys,
- TouchPositionCorrection touchPositionCorrection) {
+ ProximityInfo(final String localeStr, final int gridWidth, final int gridHeight,
+ final int minWidth, final int height, final int mostCommonKeyWidth,
+ final int mostCommonKeyHeight, final Key[] keys,
+ final TouchPositionCorrection touchPositionCorrection) {
if (TextUtils.isEmpty(localeStr)) {
mLocaleStr = "";
} else {
@@ -81,7 +82,7 @@ public class ProximityInfo {
}
public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity,
- int rowSize, int gridWidth, int gridHeight) {
+ final int rowSize, final int gridWidth, final int gridHeight) {
final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo();
spellCheckerProximityInfo.mNativeProximityInfo =
spellCheckerProximityInfo.setProximityInfoNative("",
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java
new file mode 100644
index 000000000..971020bab
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResourceUtils;
+
+public class KeyDrawParams {
+ // XML attributes
+ public final int mKeyTextColor;
+ public final int mKeyTextInactivatedColor;
+ public final float mKeyLabelHorizontalPadding;
+ public final float mKeyHintLetterPadding;
+ public final float mKeyPopupHintLetterPadding;
+ public final float mKeyShiftedLetterHintPadding;
+ public final int mKeyTextShadowColor;
+ public final float mKeyTextShadowRadius;
+ public final Drawable mKeyBackground;
+ public final int mKeyHintLetterColor;
+ public final int mKeyHintLabelColor;
+ public final int mKeyShiftedLetterHintInactivatedColor;
+ public final int mKeyShiftedLetterHintActivatedColor;
+
+ private final Typeface mKeyTypefaceFromKeyboardView;
+ private final float mKeyLetterRatio;
+ private final int mKeyLetterSizeFromKeyboardView;
+ private final float mKeyLargeLetterRatio;
+ private final float mKeyLabelRatio;
+ private final float mKeyLargeLabelRatio;
+ private final float mKeyHintLetterRatio;
+ private final float mKeyShiftedLetterHintRatio;
+ private final float mKeyHintLabelRatio;
+
+ public final Rect mPadding = new Rect();
+ public Typeface mKeyTypeface;
+ public int mKeyLetterSize;
+ public int mKeyLargeLetterSize;
+ public int mKeyLabelSize;
+ public int mKeyLargeLabelSize;
+ public int mKeyHintLetterSize;
+ public int mKeyShiftedLetterHintSize;
+ public int mKeyHintLabelSize;
+ public int mAnimAlpha;
+
+ public KeyDrawParams(final TypedArray keyboardViewAttr, final TypedArray keyAttr) {
+ mKeyBackground = keyboardViewAttr.getDrawable(R.styleable.KeyboardView_keyBackground);
+ mKeyBackground.getPadding(mPadding);
+
+ mKeyLetterRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyLetterSize);
+ mKeyLetterSizeFromKeyboardView = ResourceUtils.getDimensionPixelSize(keyAttr,
+ R.styleable.Keyboard_Key_keyLetterSize);
+ mKeyLabelRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyLabelSize);
+ mKeyLabelSize = ResourceUtils.getDimensionPixelSize(keyAttr,
+ R.styleable.Keyboard_Key_keyLabelSize);
+ mKeyLargeLabelRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyLargeLabelRatio);
+ mKeyLargeLetterRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyLargeLetterRatio);
+ mKeyHintLetterRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyHintLetterRatio);
+ mKeyShiftedLetterHintRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyShiftedLetterHintRatio);
+ mKeyHintLabelRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyHintLabelRatio);
+ mKeyLabelHorizontalPadding = keyAttr.getDimension(
+ R.styleable.Keyboard_Key_keyLabelHorizontalPadding, 0);
+ mKeyHintLetterPadding = keyAttr.getDimension(
+ R.styleable.Keyboard_Key_keyHintLetterPadding, 0);
+ mKeyPopupHintLetterPadding = keyAttr.getDimension(
+ R.styleable.Keyboard_Key_keyPopupHintLetterPadding, 0);
+ mKeyShiftedLetterHintPadding = keyAttr.getDimension(
+ R.styleable.Keyboard_Key_keyShiftedLetterHintPadding, 0);
+ mKeyTextColor = keyAttr.getColor(
+ R.styleable.Keyboard_Key_keyTextColor, Color.WHITE);
+ mKeyTextInactivatedColor = keyAttr.getColor(
+ R.styleable.Keyboard_Key_keyTextInactivatedColor, Color.WHITE);
+ mKeyHintLetterColor = keyAttr.getColor(
+ R.styleable.Keyboard_Key_keyHintLetterColor, Color.TRANSPARENT);
+ mKeyHintLabelColor = keyAttr.getColor(
+ R.styleable.Keyboard_Key_keyHintLabelColor, Color.TRANSPARENT);
+ mKeyShiftedLetterHintInactivatedColor = keyAttr.getColor(
+ R.styleable.Keyboard_Key_keyShiftedLetterHintInactivatedColor, Color.TRANSPARENT);
+ mKeyShiftedLetterHintActivatedColor = keyAttr.getColor(
+ R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor, Color.TRANSPARENT);
+ mKeyTypefaceFromKeyboardView = Typeface.defaultFromStyle(
+ keyAttr.getInt(R.styleable.Keyboard_Key_keyTypeface, Typeface.NORMAL));
+ mKeyTextShadowColor = keyAttr.getColor(
+ R.styleable.Keyboard_Key_keyTextShadowColor, Color.TRANSPARENT);
+ mKeyTextShadowRadius = keyAttr.getFloat(
+ R.styleable.Keyboard_Key_keyTextShadowRadius, 0f);
+ }
+
+ public void updateParams(final Keyboard keyboard) {
+ mKeyTypeface = (keyboard.mKeyTypeface != null)
+ ? keyboard.mKeyTypeface : mKeyTypefaceFromKeyboardView;
+ final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
+ mKeyLetterSize = selectTextSizeFromDimensionOrRatio(keyHeight,
+ mKeyLetterSizeFromKeyboardView, mKeyLetterRatio,
+ mKeyLetterSizeFromKeyboardView);
+ // Override if size/ratio is specified in Keyboard.
+ mKeyLetterSize = selectTextSizeFromDimensionOrRatio(keyHeight, keyboard.mKeyLetterSize,
+ keyboard.mKeyLetterRatio, mKeyLetterSize);
+ if (ResourceUtils.isValidFraction(mKeyLabelRatio)) {
+ mKeyLabelSize = (int)(keyHeight * mKeyLabelRatio);
+ }
+ mKeyLargeLabelSize = (int)(keyHeight * mKeyLargeLabelRatio);
+ mKeyLargeLetterSize = (int)(keyHeight * mKeyLargeLetterRatio);
+ mKeyHintLetterSize = selectTextSizeFromKeyboardOrView(keyHeight,
+ keyboard.mKeyHintLetterRatio, mKeyHintLetterRatio);
+ mKeyShiftedLetterHintSize = selectTextSizeFromKeyboardOrView(keyHeight,
+ keyboard.mKeyShiftedLetterHintRatio, mKeyShiftedLetterHintRatio);
+ mKeyHintLabelSize = (int)(keyHeight * mKeyHintLabelRatio);
+ }
+
+ private static final int selectTextSizeFromDimensionOrRatio(final int keyHeight,
+ final int dimens, final float ratio, final int defaultDimens) {
+ if (ResourceUtils.isValidDimensionPixelSize(dimens)) {
+ return dimens;
+ }
+ if (ResourceUtils.isValidFraction(ratio)) {
+ return (int)(keyHeight * ratio);
+ }
+ return defaultDimens;
+ }
+
+ private static final int selectTextSizeFromKeyboardOrView(final int keyHeight,
+ final float ratioFromKeyboard, final float ratioFromView) {
+ final float ratio = ResourceUtils.isValidFraction(ratioFromKeyboard)
+ ? ratioFromKeyboard : ratioFromView;
+ return (int)(keyHeight * ratio);
+ }
+
+ public void blendAlpha(final Paint paint) {
+ final int color = paint.getColor();
+ paint.setARGB((paint.getAlpha() * mAnimAlpha) / Constants.Color.ALPHA_OPAQUE,
+ Color.red(color), Color.green(color), Color.blue(color));
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java
new file mode 100644
index 000000000..a3a38507f
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.res.TypedArray;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResourceUtils;
+
+public class KeyPreviewDrawParams {
+ // XML attributes.
+ public final Drawable mPreviewBackground;
+ public final Drawable mPreviewLeftBackground;
+ public final Drawable mPreviewRightBackground;
+ public final int mPreviewTextColor;
+ public final int mPreviewOffset;
+ public final int mPreviewHeight;
+ public final int mLingerTimeout;
+
+ private final float mPreviewTextRatio;
+
+ // The graphical geometry of the key preview.
+ // <-width->
+ // +-------+ ^
+ // | | |
+ // |preview| height (visible)
+ // | | |
+ // + + ^ v
+ // \ / |offset
+ // +-\ /-+ v
+ // | +-+ |
+ // |parent |
+ // | key|
+ // +-------+
+ // The background of a {@link TextView} being used for a key preview may have invisible
+ // paddings. To align the more keys keyboard panel's visible part with the visible part of
+ // the background, we need to record the width and height of key preview that don't include
+ // invisible paddings.
+ public int mPreviewVisibleWidth;
+ public int mPreviewVisibleHeight;
+ // The key preview may have an arbitrary offset and its background that may have a bottom
+ // padding. To align the more keys keyboard and the key preview we also need to record the
+ // offset between the top edge of parent key and the bottom of the visible part of key
+ // preview background.
+ public int mPreviewVisibleOffset;
+
+ public Typeface mKeyTypeface;
+ public int mPreviewTextSize;
+ public int mKeyLetterSize;
+ public final int[] mCoordinates = new int[2];
+
+ private static final int PREVIEW_ALPHA = 240;
+
+ public KeyPreviewDrawParams(final TypedArray keyboardViewAttr, final TypedArray keyAttr) {
+ mPreviewBackground = keyboardViewAttr.getDrawable(
+ R.styleable.KeyboardView_keyPreviewBackground);
+ mPreviewLeftBackground = keyboardViewAttr.getDrawable(
+ R.styleable.KeyboardView_keyPreviewLeftBackground);
+ mPreviewRightBackground = keyboardViewAttr.getDrawable(
+ R.styleable.KeyboardView_keyPreviewRightBackground);
+ setAlpha(mPreviewBackground, PREVIEW_ALPHA);
+ setAlpha(mPreviewLeftBackground, PREVIEW_ALPHA);
+ setAlpha(mPreviewRightBackground, PREVIEW_ALPHA);
+ mPreviewOffset = keyboardViewAttr.getDimensionPixelOffset(
+ R.styleable.KeyboardView_keyPreviewOffset, 0);
+ mPreviewHeight = keyboardViewAttr.getDimensionPixelSize(
+ R.styleable.KeyboardView_keyPreviewHeight, 80);
+ mLingerTimeout = keyboardViewAttr.getInt(
+ R.styleable.KeyboardView_keyPreviewLingerTimeout, 0);
+
+ mPreviewTextRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyPreviewTextRatio);
+ mPreviewTextColor = keyAttr.getColor(R.styleable.Keyboard_Key_keyPreviewTextColor, 0);
+ }
+
+ public void updateParams(final Keyboard keyboard, final KeyDrawParams keyDrawParams) {
+ final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
+ if (ResourceUtils.isValidFraction(mPreviewTextRatio)) {
+ mPreviewTextSize = (int)(keyHeight * mPreviewTextRatio);
+ }
+ mKeyLetterSize = keyDrawParams.mKeyLetterSize;
+ mKeyTypeface = keyDrawParams.mKeyTypeface;
+ }
+
+ private static void setAlpha(final Drawable drawable, final int alpha) {
+ if (drawable == null) return;
+ drawable.setAlpha(alpha);
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index 13214bb9f..2a57caa5f 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -56,59 +56,20 @@ public class KeySpecParser {
private static final char ESCAPE_CHAR = '\\';
private static final char LABEL_END = '|';
private static final String PREFIX_TEXT = "!text/";
- private static final String PREFIX_ICON = "!icon/";
+ static final String PREFIX_ICON = "!icon/";
private static final String PREFIX_CODE = "!code/";
private static final String PREFIX_HEX = "0x";
private static final String ADDITIONAL_MORE_KEY_MARKER = "%";
- public static class MoreKeySpec {
- public final int mCode;
- public final String mLabel;
- public final String mOutputText;
- public final int mIconId;
-
- public MoreKeySpec(final String moreKeySpec, boolean needsToUpperCase, Locale locale,
- final KeyboardCodesSet codesSet) {
- mLabel = toUpperCaseOfStringForLocale(getLabel(moreKeySpec),
- needsToUpperCase, locale);
- final int code = toUpperCaseOfCodeForLocale(getCode(moreKeySpec, codesSet),
- needsToUpperCase, locale);
- if (code == Keyboard.CODE_UNSPECIFIED) {
- // Some letter, for example German Eszett (U+00DF: "ß"), has multiple characters
- // upper case representation ("SS").
- mCode = Keyboard.CODE_OUTPUT_TEXT;
- mOutputText = mLabel;
- } else {
- mCode = code;
- mOutputText = toUpperCaseOfStringForLocale(getOutputText(moreKeySpec),
- needsToUpperCase, locale);
- }
- mIconId = getIconId(moreKeySpec);
- }
-
- @Override
- public String toString() {
- final String label = (mIconId == KeyboardIconsSet.ICON_UNDEFINED ? mLabel
- : PREFIX_ICON + KeyboardIconsSet.getIconName(mIconId));
- final String output = (mCode == Keyboard.CODE_OUTPUT_TEXT ? mOutputText
- : Keyboard.printableCode(mCode));
- if (StringUtils.codePointCount(label) == 1 && label.codePointAt(0) == mCode) {
- return output;
- } else {
- return label + "|" + output;
- }
- }
- }
-
private KeySpecParser() {
// Intentional empty constructor for utility class.
}
- private static boolean hasIcon(String moreKeySpec) {
+ private static boolean hasIcon(final String moreKeySpec) {
return moreKeySpec.startsWith(PREFIX_ICON);
}
- private static boolean hasCode(String moreKeySpec) {
+ private static boolean hasCode(final String moreKeySpec) {
final int end = indexOfLabelEnd(moreKeySpec, 0);
if (end > 0 && end + 1 < moreKeySpec.length() && moreKeySpec.startsWith(
PREFIX_CODE, end + 1)) {
@@ -117,7 +78,7 @@ public class KeySpecParser {
return false;
}
- private static String parseEscape(String text) {
+ private static String parseEscape(final String text) {
if (text.indexOf(ESCAPE_CHAR) < 0) {
return text;
}
@@ -136,7 +97,7 @@ public class KeySpecParser {
return sb.toString();
}
- private static int indexOfLabelEnd(String moreKeySpec, int start) {
+ private static int indexOfLabelEnd(final String moreKeySpec, final int start) {
if (moreKeySpec.indexOf(ESCAPE_CHAR, start) < 0) {
final int end = moreKeySpec.indexOf(LABEL_END, start);
if (end == 0) {
@@ -157,7 +118,7 @@ public class KeySpecParser {
return -1;
}
- public static String getLabel(String moreKeySpec) {
+ public static String getLabel(final String moreKeySpec) {
if (hasIcon(moreKeySpec)) {
return null;
}
@@ -170,7 +131,7 @@ public class KeySpecParser {
return label;
}
- private static String getOutputTextInternal(String moreKeySpec) {
+ private static String getOutputTextInternal(final String moreKeySpec) {
final int end = indexOfLabelEnd(moreKeySpec, 0);
if (end <= 0) {
return null;
@@ -181,7 +142,7 @@ public class KeySpecParser {
return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1));
}
- static String getOutputText(String moreKeySpec) {
+ static String getOutputText(final String moreKeySpec) {
if (hasCode(moreKeySpec)) {
return null;
}
@@ -205,7 +166,7 @@ public class KeySpecParser {
return (StringUtils.codePointCount(label) == 1) ? null : label;
}
- static int getCode(String moreKeySpec, KeyboardCodesSet codesSet) {
+ static int getCode(final String moreKeySpec, final KeyboardCodesSet codesSet) {
if (hasCode(moreKeySpec)) {
final int end = indexOfLabelEnd(moreKeySpec, 0);
if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
@@ -230,7 +191,8 @@ public class KeySpecParser {
return Keyboard.CODE_OUTPUT_TEXT;
}
- public static int parseCode(String text, KeyboardCodesSet codesSet, int defCode) {
+ public static int parseCode(final String text, final KeyboardCodesSet codesSet,
+ final int defCode) {
if (text == null) return defCode;
if (text.startsWith(PREFIX_CODE)) {
return codesSet.getCode(text.substring(PREFIX_CODE.length()));
@@ -241,7 +203,7 @@ public class KeySpecParser {
}
}
- public static int getIconId(String moreKeySpec) {
+ public static int getIconId(final String moreKeySpec) {
if (moreKeySpec != null && hasIcon(moreKeySpec)) {
final int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length());
final String name = (end < 0) ? moreKeySpec.substring(PREFIX_ICON.length())
@@ -251,7 +213,7 @@ public class KeySpecParser {
return KeyboardIconsSet.ICON_UNDEFINED;
}
- private static <T> ArrayList<T> arrayAsList(T[] array, int start, int end) {
+ private static <T> ArrayList<T> arrayAsList(final T[] array, final int start, final int end) {
if (array == null) {
throw new NullPointerException();
}
@@ -268,7 +230,7 @@ public class KeySpecParser {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
- private static String[] filterOutEmptyString(String[] array) {
+ private static String[] filterOutEmptyString(final String[] array) {
if (array == null) {
return EMPTY_STRING_ARRAY;
}
@@ -289,8 +251,8 @@ public class KeySpecParser {
return out.toArray(new String[out.size()]);
}
- public static String[] insertAdditionalMoreKeys(String[] moreKeySpecs,
- String[] additionalMoreKeySpecs) {
+ public static String[] insertAdditionalMoreKeys(final String[] moreKeySpecs,
+ final String[] additionalMoreKeySpecs) {
final String[] moreKeys = filterOutEmptyString(moreKeySpecs);
final String[] additionalMoreKeys = filterOutEmptyString(additionalMoreKeySpecs);
final int moreKeysCount = moreKeys.length;
@@ -357,12 +319,13 @@ public class KeySpecParser {
@SuppressWarnings("serial")
public static class KeySpecParserError extends RuntimeException {
- public KeySpecParserError(String message) {
+ public KeySpecParserError(final String message) {
super(message);
}
}
- public static String resolveTextReference(String rawText, KeyboardTextsSet textsSet) {
+ public static String resolveTextReference(final String rawText,
+ final KeyboardTextsSet textsSet) {
int level = 0;
String text = rawText;
StringBuilder sb;
@@ -408,7 +371,7 @@ public class KeySpecParser {
return text;
}
- private static int searchTextNameEnd(String text, int start) {
+ private static int searchTextNameEnd(final String text, final int start) {
final int size = text.length();
for (int pos = start; pos < size; pos++) {
final char c = text.charAt(pos);
@@ -421,7 +384,7 @@ public class KeySpecParser {
return size;
}
- public static String[] parseCsvString(String rawText, KeyboardTextsSet textsSet) {
+ public static String[] parseCsvString(final String rawText, final KeyboardTextsSet textsSet) {
final String text = resolveTextReference(rawText, textsSet);
final int size = text.length();
if (size == 0) {
@@ -460,7 +423,8 @@ public class KeySpecParser {
return list.toArray(new String[list.size()]);
}
- public static int getIntValue(String[] moreKeys, String key, int defaultValue) {
+ public static int getIntValue(final String[] moreKeys, final String key,
+ final int defaultValue) {
if (moreKeys == null) {
return defaultValue;
}
@@ -486,7 +450,7 @@ public class KeySpecParser {
return value;
}
- public static boolean getBooleanValue(String[] moreKeys, String key) {
+ public static boolean getBooleanValue(final String[] moreKeys, final String key) {
if (moreKeys == null) {
return false;
}
@@ -502,8 +466,8 @@ public class KeySpecParser {
return value;
}
- public static int toUpperCaseOfCodeForLocale(int code, boolean needsToUpperCase,
- Locale locale) {
+ public static int toUpperCaseOfCodeForLocale(final int code, final boolean needsToUpperCase,
+ final Locale locale) {
if (!Keyboard.isLetterCode(code) || !needsToUpperCase) return code;
final String text = new String(new int[] { code } , 0, 1);
final String casedText = KeySpecParser.toUpperCaseOfStringForLocale(
@@ -512,8 +476,8 @@ public class KeySpecParser {
? casedText.codePointAt(0) : CODE_UNSPECIFIED;
}
- public static String toUpperCaseOfStringForLocale(String text, boolean needsToUpperCase,
- Locale locale) {
+ public static String toUpperCaseOfStringForLocale(final String text,
+ final boolean needsToUpperCase, final Locale locale) {
if (text == null || !needsToUpperCase) return text;
return text.toUpperCase(locale);
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java
new file mode 100644
index 000000000..e8cacf9e7
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.res.TypedArray;
+
+public abstract class KeyStyle {
+ private final KeyboardTextsSet mTextsSet;
+
+ public abstract String[] getStringArray(TypedArray a, int index);
+ public abstract String getString(TypedArray a, int index);
+ public abstract int getInt(TypedArray a, int index, int defaultValue);
+ public abstract int getFlag(TypedArray a, int index);
+
+ protected KeyStyle(final KeyboardTextsSet textsSet) {
+ mTextsSet = textsSet;
+ }
+
+ protected String parseString(final TypedArray a, final int index) {
+ if (a.hasValue(index)) {
+ return KeySpecParser.resolveTextReference(a.getString(index), mTextsSet);
+ }
+ return null;
+ }
+
+ protected String[] parseStringArray(final TypedArray a, final int index) {
+ if (a.hasValue(index)) {
+ return KeySpecParser.parseCsvString(a.getString(index), mTextsSet);
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java
index e40cf45cc..71fd30563 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java
@@ -20,7 +20,6 @@ import android.content.res.TypedArray;
import android.util.Log;
import android.util.SparseArray;
-import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.XmlParseUtils;
@@ -30,75 +29,62 @@ import org.xmlpull.v1.XmlPullParserException;
import java.util.HashMap;
-public class KeyStyles {
- private static final String TAG = KeyStyles.class.getSimpleName();
+public class KeyStylesSet {
+ private static final String TAG = KeyStylesSet.class.getSimpleName();
private static final boolean DEBUG = false;
- final HashMap<String, KeyStyle> mStyles = CollectionUtils.newHashMap();
+ private final HashMap<String, KeyStyle> mStyles = CollectionUtils.newHashMap();
- final KeyboardTextsSet mTextsSet;
+ private final KeyboardTextsSet mTextsSet;
private final KeyStyle mEmptyKeyStyle;
private static final String EMPTY_STYLE_NAME = "<empty>";
- public KeyStyles(KeyboardTextsSet textsSet) {
+ public KeyStylesSet(final KeyboardTextsSet textsSet) {
mTextsSet = textsSet;
- mEmptyKeyStyle = new EmptyKeyStyle();
+ mEmptyKeyStyle = new EmptyKeyStyle(textsSet);
mStyles.put(EMPTY_STYLE_NAME, mEmptyKeyStyle);
}
- public abstract class KeyStyle {
- public abstract String[] getStringArray(TypedArray a, int index);
- public abstract String getString(TypedArray a, int index);
- public abstract int getInt(TypedArray a, int index, int defaultValue);
- public abstract int getFlag(TypedArray a, int index);
-
- protected String parseString(TypedArray a, int index) {
- if (a.hasValue(index)) {
- return KeySpecParser.resolveTextReference(a.getString(index), mTextsSet);
- }
- return null;
- }
-
- protected String[] parseStringArray(TypedArray a, int index) {
- if (a.hasValue(index)) {
- return KeySpecParser.parseCsvString(a.getString(index), mTextsSet);
- }
- return null;
+ private static class EmptyKeyStyle extends KeyStyle {
+ EmptyKeyStyle(final KeyboardTextsSet textsSet) {
+ super(textsSet);
}
- }
- class EmptyKeyStyle extends KeyStyle {
@Override
- public String[] getStringArray(TypedArray a, int index) {
+ public String[] getStringArray(final TypedArray a, final int index) {
return parseStringArray(a, index);
}
@Override
- public String getString(TypedArray a, int index) {
+ public String getString(final TypedArray a, final int index) {
return parseString(a, index);
}
@Override
- public int getInt(TypedArray a, int index, int defaultValue) {
+ public int getInt(final TypedArray a, final int index, final int defaultValue) {
return a.getInt(index, defaultValue);
}
@Override
- public int getFlag(TypedArray a, int index) {
+ public int getFlag(final TypedArray a, final int index) {
return a.getInt(index, 0);
}
}
- private class DeclaredKeyStyle extends KeyStyle {
+ private static class DeclaredKeyStyle extends KeyStyle {
+ private final HashMap<String, KeyStyle> mStyles;
private final String mParentStyleName;
private final SparseArray<Object> mStyleAttributes = CollectionUtils.newSparseArray();
- public DeclaredKeyStyle(String parentStyleName) {
+ public DeclaredKeyStyle(final String parentStyleName, final KeyboardTextsSet textsSet,
+ final HashMap<String, KeyStyle> styles) {
+ super(textsSet);
mParentStyleName = parentStyleName;
+ mStyles = styles;
}
@Override
- public String[] getStringArray(TypedArray a, int index) {
+ public String[] getStringArray(final TypedArray a, final int index) {
if (a.hasValue(index)) {
return parseStringArray(a, index);
}
@@ -111,7 +97,7 @@ public class KeyStyles {
}
@Override
- public String getString(TypedArray a, int index) {
+ public String getString(final TypedArray a, final int index) {
if (a.hasValue(index)) {
return parseString(a, index);
}
@@ -124,7 +110,7 @@ public class KeyStyles {
}
@Override
- public int getInt(TypedArray a, int index, int defaultValue) {
+ public int getInt(final TypedArray a, final int index, final int defaultValue) {
if (a.hasValue(index)) {
return a.getInt(index, defaultValue);
}
@@ -137,7 +123,7 @@ public class KeyStyles {
}
@Override
- public int getFlag(TypedArray a, int index) {
+ public int getFlag(final TypedArray a, final int index) {
int flags = a.getInt(index, 0);
final Object value = mStyleAttributes.get(index);
if (value != null) {
@@ -147,7 +133,7 @@ public class KeyStyles {
return flags | parentStyle.getFlag(a, index);
}
- void readKeyAttributes(TypedArray keyAttr) {
+ public void readKeyAttributes(final TypedArray keyAttr) {
// TODO: Currently not all Key attributes can be declared as style.
readString(keyAttr, R.styleable.Keyboard_Key_code);
readString(keyAttr, R.styleable.Keyboard_Key_altCode);
@@ -165,38 +151,38 @@ public class KeyStyles {
readFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
}
- private void readString(TypedArray a, int index) {
+ private void readString(final TypedArray a, final int index) {
if (a.hasValue(index)) {
mStyleAttributes.put(index, parseString(a, index));
}
}
- private void readInt(TypedArray a, int index) {
+ private void readInt(final TypedArray a, final int index) {
if (a.hasValue(index)) {
mStyleAttributes.put(index, a.getInt(index, 0));
}
}
- private void readFlag(TypedArray a, int index) {
+ private void readFlag(final TypedArray a, final int index) {
if (a.hasValue(index)) {
final Integer value = (Integer)mStyleAttributes.get(index);
mStyleAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
}
}
- private void readStringArray(TypedArray a, int index) {
+ private void readStringArray(final TypedArray a, final int index) {
if (a.hasValue(index)) {
mStyleAttributes.put(index, parseStringArray(a, index));
}
}
}
- public void parseKeyStyleAttributes(TypedArray keyStyleAttr, TypedArray keyAttrs,
- XmlPullParser parser) throws XmlPullParserException {
+ public void parseKeyStyleAttributes(final TypedArray keyStyleAttr, final TypedArray keyAttrs,
+ final 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));
+ KeyboardBuilder.TAG_KEY_STYLE, styleName));
if (mStyles.containsKey(styleName)) {
Log.d(TAG, "key-style " + styleName + " is overridden at "
+ parser.getPositionDescription());
@@ -211,12 +197,12 @@ public class KeyStyles {
"Unknown parentStyle " + parentStyleName, parser);
}
}
- final DeclaredKeyStyle style = new DeclaredKeyStyle(parentStyleName);
+ final DeclaredKeyStyle style = new DeclaredKeyStyle(parentStyleName, mTextsSet, mStyles);
style.readKeyAttributes(keyAttrs);
mStyles.put(styleName, style);
}
- public KeyStyle getKeyStyle(TypedArray keyAttr, XmlPullParser parser)
+ public KeyStyle getKeyStyle(final TypedArray keyAttr, final XmlPullParser parser)
throws XmlParseUtils.ParseException {
if (!keyAttr.hasValue(R.styleable.Keyboard_Key_keyStyle)) {
return mEmptyKeyStyle;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
new file mode 100644
index 000000000..3d1045f88
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.Typeface;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.view.InflateException;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResourceUtils;
+import com.android.inputmethod.latin.StringUtils;
+import com.android.inputmethod.latin.SubtypeLocale;
+import com.android.inputmethod.latin.XmlParseUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * Keyboard Building helper.
+ *
+ * This class parses Keyboard XML file and eventually build a Keyboard.
+ * The Keyboard XML file looks like:
+ * <pre>
+ * &lt;!-- xml/keyboard.xml --&gt;
+ * &lt;Keyboard keyboard_attributes*&gt;
+ * &lt;!-- Keyboard Content --&gt;
+ * &lt;Row row_attributes*&gt;
+ * &lt;!-- Row Content --&gt;
+ * &lt;Key key_attributes* /&gt;
+ * &lt;Spacer horizontalGap="32.0dp" /&gt;
+ * &lt;include keyboardLayout="@xml/other_keys"&gt;
+ * ...
+ * &lt;/Row&gt;
+ * &lt;include keyboardLayout="@xml/other_rows"&gt;
+ * ...
+ * &lt;/Keyboard&gt;
+ * </pre>
+ * The XML file which is included in other file must have &lt;merge&gt; as root element,
+ * such as:
+ * <pre>
+ * &lt;!-- xml/other_keys.xml --&gt;
+ * &lt;merge&gt;
+ * &lt;Key key_attributes* /&gt;
+ * ...
+ * &lt;/merge&gt;
+ * </pre>
+ * and
+ * <pre>
+ * &lt;!-- xml/other_rows.xml --&gt;
+ * &lt;merge&gt;
+ * &lt;Row row_attributes*&gt;
+ * &lt;Key key_attributes* /&gt;
+ * &lt;/Row&gt;
+ * ...
+ * &lt;/merge&gt;
+ * </pre>
+ * You can also use switch-case-default tags to select Rows and Keys.
+ * <pre>
+ * &lt;switch&gt;
+ * &lt;case case_attribute*&gt;
+ * &lt;!-- Any valid tags at switch position --&gt;
+ * &lt;/case&gt;
+ * ...
+ * &lt;default&gt;
+ * &lt;!-- Any valid tags at switch position --&gt;
+ * &lt;/default&gt;
+ * &lt;/switch&gt;
+ * </pre>
+ * You can declare Key style and specify styles within Key tags.
+ * <pre>
+ * &lt;switch&gt;
+ * &lt;case mode="email"&gt;
+ * &lt;key-style styleName="f1-key" parentStyle="modifier-key"
+ * keyLabel=".com"
+ * /&gt;
+ * &lt;/case&gt;
+ * &lt;case mode="url"&gt;
+ * &lt;key-style styleName="f1-key" parentStyle="modifier-key"
+ * keyLabel="http://"
+ * /&gt;
+ * &lt;/case&gt;
+ * &lt;/switch&gt;
+ * ...
+ * &lt;Key keyStyle="shift-key" ... /&gt;
+ * </pre>
+ */
+
+public class KeyboardBuilder<KP extends KeyboardParams> {
+ private static final String BUILDER_TAG = "Keyboard.Builder";
+ private static final boolean DEBUG = false;
+
+ // Keyboard XML Tags
+ private static final String TAG_KEYBOARD = "Keyboard";
+ private static final String TAG_ROW = "Row";
+ private static final String TAG_KEY = "Key";
+ private static final String TAG_SPACER = "Spacer";
+ private static final String TAG_INCLUDE = "include";
+ private static final String TAG_MERGE = "merge";
+ private static final String TAG_SWITCH = "switch";
+ private static final String TAG_CASE = "case";
+ private static final String TAG_DEFAULT = "default";
+ public static final String TAG_KEY_STYLE = "key-style";
+
+ private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
+ private static final int DEFAULT_KEYBOARD_ROWS = 4;
+
+ protected final KP mParams;
+ protected final Context mContext;
+ protected final Resources mResources;
+ private final DisplayMetrics mDisplayMetrics;
+
+ private int mCurrentY = 0;
+ private KeyboardRow mCurrentRow = null;
+ private boolean mLeftEdge;
+ private boolean mTopEdge;
+ private Key mRightEdgeKey = null;
+
+ public KeyboardBuilder(final Context context, final KP params) {
+ mContext = context;
+ final Resources res = context.getResources();
+ mResources = res;
+ mDisplayMetrics = res.getDisplayMetrics();
+
+ mParams = params;
+
+ params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
+ params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
+ }
+
+ public void setAutoGenerate(final KeysCache keysCache) {
+ mParams.mKeysCache = keysCache;
+ }
+
+ public KeyboardBuilder<KP> load(final int xmlId, final KeyboardId id) {
+ mParams.mId = id;
+ final XmlResourceParser parser = mResources.getXml(xmlId);
+ try {
+ parseKeyboard(parser);
+ } catch (XmlPullParserException e) {
+ Log.w(BUILDER_TAG, "keyboard XML parse error: " + e);
+ throw new IllegalArgumentException(e);
+ } catch (IOException e) {
+ Log.w(BUILDER_TAG, "keyboard XML parse error: " + e);
+ throw new RuntimeException(e);
+ } finally {
+ parser.close();
+ }
+ return this;
+ }
+
+ // TODO: Remove this method.
+ public void setTouchPositionCorrectionEnabled(final boolean enabled) {
+ mParams.mTouchPositionCorrection.setEnabled(enabled);
+ }
+
+ public void setProximityCharsCorrectionEnabled(final boolean enabled) {
+ mParams.mProximityCharsCorrectionEnabled = enabled;
+ }
+
+ public Keyboard build() {
+ return new Keyboard(mParams);
+ }
+
+ private int mIndent;
+ private static final String SPACES = " ";
+
+ private static String spaces(final int count) {
+ return (count < SPACES.length()) ? SPACES.substring(0, count) : SPACES;
+ }
+
+ private void startTag(final String format, final Object ... args) {
+ Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args));
+ }
+
+ private void endTag(final String format, final Object ... args) {
+ Log.d(BUILDER_TAG, String.format(spaces(mIndent-- * 2) + format, args));
+ }
+
+ private void startEndTag(final String format, final Object ... args) {
+ Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args));
+ mIndent--;
+ }
+
+ private void parseKeyboard(final XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ if (DEBUG) startTag("<%s> %s", TAG_KEYBOARD, mParams.mId);
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_KEYBOARD.equals(tag)) {
+ parseKeyboardAttributes(parser);
+ startKeyboard();
+ parseKeyboardContent(parser, false);
+ break;
+ } else {
+ throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD);
+ }
+ }
+ }
+ }
+
+ private void parseKeyboardAttributes(final XmlPullParser parser) {
+ final int displayWidth = mDisplayMetrics.widthPixels;
+ final TypedArray keyboardAttr = mContext.obtainStyledAttributes(
+ Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle,
+ R.style.Keyboard);
+ final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Key);
+ try {
+ final int displayHeight = mDisplayMetrics.heightPixels;
+ final String keyboardHeightString = ResourceUtils.getDeviceOverrideValue(
+ mResources, R.array.keyboard_heights, null);
+ final float keyboardHeight;
+ if (keyboardHeightString != null) {
+ keyboardHeight = Float.parseFloat(keyboardHeightString)
+ * mDisplayMetrics.density;
+ } else {
+ keyboardHeight = keyboardAttr.getDimension(
+ R.styleable.Keyboard_keyboardHeight, displayHeight / 2);
+ }
+ final float maxKeyboardHeight = ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2);
+ float minKeyboardHeight = ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2);
+ if (minKeyboardHeight < 0) {
+ // Specified fraction was negative, so it should be calculated against display
+ // width.
+ minKeyboardHeight = -ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2);
+ }
+ final KeyboardParams params = mParams;
+ // Keyboard height will not exceed maxKeyboardHeight and will not be less than
+ // minKeyboardHeight.
+ params.mOccupiedHeight = (int)Math.max(
+ Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
+ params.mOccupiedWidth = params.mId.mWidth;
+ params.mTopPadding = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0);
+ params.mBottomPadding = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0);
+ params.mHorizontalEdgesPadding = (int)ResourceUtils.getDimensionOrFraction(
+ keyboardAttr,
+ R.styleable.Keyboard_keyboardHorizontalEdgesPadding,
+ mParams.mOccupiedWidth, 0);
+
+ params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2
+ - params.mHorizontalCenterPadding;
+ params.mDefaultKeyWidth = (int)ResourceUtils.getDimensionOrFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth,
+ params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS);
+ params.mHorizontalGap = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0);
+ params.mVerticalGap = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0);
+ params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding
+ - params.mBottomPadding + params.mVerticalGap;
+ params.mDefaultRowHeight = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_rowHeight, params.mBaseHeight,
+ params.mBaseHeight / DEFAULT_KEYBOARD_ROWS);
+
+ if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyTypeface)) {
+ params.mKeyTypeface = Typeface.defaultFromStyle(keyAttr.getInt(
+ R.styleable.Keyboard_Key_keyTypeface, Typeface.NORMAL));
+ }
+ params.mKeyLetterRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyLetterSize);
+ params.mKeyLetterSize = ResourceUtils.getDimensionPixelSize(keyAttr,
+ R.styleable.Keyboard_Key_keyLetterSize);
+ params.mKeyHintLetterRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyHintLetterRatio);
+ params.mKeyShiftedLetterHintRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyShiftedLetterHintRatio);
+
+ params.mMoreKeysTemplate = keyboardAttr.getResourceId(
+ R.styleable.Keyboard_moreKeysTemplate, 0);
+ params.mMaxMoreKeysKeyboardColumn = keyAttr.getInt(
+ R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);
+
+ params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0);
+ params.mIconsSet.loadIcons(keyboardAttr);
+ final String language = params.mId.mLocale.getLanguage();
+ params.mCodesSet.setLanguage(language);
+ params.mTextsSet.setLanguage(language);
+ final RunInLocale<Void> job = new RunInLocale<Void>() {
+ @Override
+ protected Void job(Resources res) {
+ params.mTextsSet.loadStringResources(mContext);
+ return null;
+ }
+ };
+ // Null means the current system locale.
+ final Locale locale = SubtypeLocale.isNoLanguage(params.mId.mSubtype)
+ ? null : params.mId.mLocale;
+ job.runInLocale(mResources, locale);
+
+ final int resourceId = keyboardAttr.getResourceId(
+ R.styleable.Keyboard_touchPositionCorrectionData, 0);
+ params.mTouchPositionCorrection.setEnabled(resourceId != 0);
+ if (resourceId != 0) {
+ final String[] data = mResources.getStringArray(resourceId);
+ params.mTouchPositionCorrection.load(data);
+ }
+ } finally {
+ keyAttr.recycle();
+ keyboardAttr.recycle();
+ }
+ }
+
+ private void parseKeyboardContent(final XmlPullParser parser, final boolean skip)
+ throws XmlPullParserException, IOException {
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_ROW.equals(tag)) {
+ final KeyboardRow row = parseRowAttributes(parser);
+ 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);
+ } else if (TAG_SWITCH.equals(tag)) {
+ parseSwitchKeyboardContent(parser, skip);
+ } else if (TAG_KEY_STYLE.equals(tag)) {
+ parseKeyStyle(parser, skip);
+ } else {
+ throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW);
+ }
+ } 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)) {
+ break;
+ } else {
+ throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW);
+ }
+ }
+ }
+ }
+
+ private KeyboardRow parseRowAttributes(final XmlPullParser parser)
+ throws XmlPullParserException {
+ final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard);
+ try {
+ if (a.hasValue(R.styleable.Keyboard_horizontalGap)) {
+ throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap");
+ }
+ if (a.hasValue(R.styleable.Keyboard_verticalGap)) {
+ throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap");
+ }
+ return new KeyboardRow(mResources, mParams, parser, mCurrentY);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ private void parseRowContent(final XmlPullParser parser, final KeyboardRow row,
+ final boolean skip) throws XmlPullParserException, IOException {
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_KEY.equals(tag)) {
+ parseKey(parser, row, skip);
+ } else if (TAG_SPACER.equals(tag)) {
+ parseSpacer(parser, row, skip);
+ } else if (TAG_INCLUDE.equals(tag)) {
+ parseIncludeRowContent(parser, row, skip);
+ } else if (TAG_SWITCH.equals(tag)) {
+ parseSwitchRowContent(parser, row, skip);
+ } else if (TAG_KEY_STYLE.equals(tag)) {
+ parseKeyStyle(parser, skip);
+ } else {
+ throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
+ }
+ } else if (event == XmlPullParser.END_TAG) {
+ final String tag = parser.getName();
+ if (DEBUG) endTag("</%s>", tag);
+ if (TAG_ROW.equals(tag)) {
+ if (!skip) {
+ endRow(row);
+ }
+ break;
+ } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)
+ || TAG_MERGE.equals(tag)) {
+ break;
+ } else {
+ throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
+ }
+ }
+ }
+ }
+
+ private void parseKey(final XmlPullParser parser, final KeyboardRow row, final boolean skip)
+ 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);
+ 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);
+ }
+ }
+
+ private void parseSpacer(final XmlPullParser parser, final KeyboardRow row, final boolean skip)
+ 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);
+ if (DEBUG) startEndTag("<%s />", TAG_SPACER);
+ XmlParseUtils.checkEndTag(TAG_SPACER, parser);
+ endKey(spacer);
+ }
+ }
+
+ private void parseIncludeKeyboardContent(final XmlPullParser parser, final boolean skip)
+ throws XmlPullParserException, IOException {
+ parseIncludeInternal(parser, null, skip);
+ }
+
+ private void parseIncludeRowContent(final XmlPullParser parser, final KeyboardRow row,
+ final boolean skip) throws XmlPullParserException, IOException {
+ parseIncludeInternal(parser, row, skip);
+ }
+
+ private void parseIncludeInternal(final XmlPullParser parser, final KeyboardRow row,
+ final boolean skip) 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,
+ R.styleable.Keyboard_Include);
+ final TypedArray keyAttr = mResources.obtainAttributes(attr,
+ R.styleable.Keyboard_Key);
+ int keyboardLayout = 0;
+ float savedDefaultKeyWidth = 0;
+ int savedDefaultKeyLabelFlags = 0;
+ int savedDefaultBackgroundType = Key.BACKGROUND_TYPE_NORMAL;
+ try {
+ XmlParseUtils.checkAttributeExists(keyboardAttr,
+ R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout",
+ TAG_INCLUDE, parser);
+ keyboardLayout = keyboardAttr.getResourceId(
+ R.styleable.Keyboard_Include_keyboardLayout, 0);
+ if (row != null) {
+ if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
+ // Override current x coordinate.
+ row.setXPos(row.getKeyX(keyAttr));
+ }
+ // TODO: Remove this if-clause and do the same as backgroundType below.
+ savedDefaultKeyWidth = row.getDefaultKeyWidth();
+ if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyWidth)) {
+ // Override default key width.
+ row.setDefaultKeyWidth(row.getKeyWidth(keyAttr));
+ }
+ savedDefaultKeyLabelFlags = row.getDefaultKeyLabelFlags();
+ // Bitwise-or default keyLabelFlag if exists.
+ row.setDefaultKeyLabelFlags(keyAttr.getInt(
+ R.styleable.Keyboard_Key_keyLabelFlags, 0)
+ | savedDefaultKeyLabelFlags);
+ savedDefaultBackgroundType = row.getDefaultBackgroundType();
+ // Override default backgroundType if exists.
+ row.setDefaultBackgroundType(keyAttr.getInt(
+ R.styleable.Keyboard_Key_backgroundType,
+ savedDefaultBackgroundType));
+ }
+ } finally {
+ keyboardAttr.recycle();
+ keyAttr.recycle();
+ }
+
+ XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
+ if (DEBUG) {
+ startEndTag("<%s keyboardLayout=%s />",TAG_INCLUDE,
+ mResources.getResourceEntryName(keyboardLayout));
+ }
+ final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout);
+ try {
+ parseMerge(parserForInclude, row, skip);
+ } finally {
+ if (row != null) {
+ // Restore default keyWidth, keyLabelFlags, and backgroundType.
+ row.setDefaultKeyWidth(savedDefaultKeyWidth);
+ row.setDefaultKeyLabelFlags(savedDefaultKeyLabelFlags);
+ row.setDefaultBackgroundType(savedDefaultBackgroundType);
+ }
+ parserForInclude.close();
+ }
+ }
+ }
+
+ private void parseMerge(final XmlPullParser parser, final KeyboardRow row, final 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) {
+ final String tag = parser.getName();
+ if (TAG_MERGE.equals(tag)) {
+ if (row == null) {
+ parseKeyboardContent(parser, skip);
+ } else {
+ parseRowContent(parser, row, skip);
+ }
+ break;
+ } else {
+ throw new XmlParseUtils.ParseException(
+ "Included keyboard layout must have <merge> root element", parser);
+ }
+ }
+ }
+ }
+
+ private void parseSwitchKeyboardContent(final XmlPullParser parser, final boolean skip)
+ throws XmlPullParserException, IOException {
+ parseSwitchInternal(parser, null, skip);
+ }
+
+ private void parseSwitchRowContent(final XmlPullParser parser, final KeyboardRow row,
+ final boolean skip) throws XmlPullParserException, IOException {
+ parseSwitchInternal(parser, row, skip);
+ }
+
+ private void parseSwitchInternal(final XmlPullParser parser, final KeyboardRow row,
+ final boolean skip) throws XmlPullParserException, IOException {
+ if (DEBUG) startTag("<%s> %s", TAG_SWITCH, mParams.mId);
+ boolean selected = false;
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event == XmlPullParser.START_TAG) {
+ final String tag = parser.getName();
+ if (TAG_CASE.equals(tag)) {
+ selected |= parseCase(parser, row, selected ? true : skip);
+ } else if (TAG_DEFAULT.equals(tag)) {
+ selected |= parseDefault(parser, row, selected ? true : skip);
+ } else {
+ throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY);
+ }
+ } else if (event == XmlPullParser.END_TAG) {
+ final String tag = parser.getName();
+ if (TAG_SWITCH.equals(tag)) {
+ if (DEBUG) endTag("</%s>", TAG_SWITCH);
+ break;
+ } else {
+ throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
+ }
+ }
+ }
+ }
+
+ private boolean parseCase(final XmlPullParser parser, final KeyboardRow row, final boolean skip)
+ throws XmlPullParserException, IOException {
+ final boolean selected = parseCaseCondition(parser);
+ if (row == null) {
+ // Processing Rows.
+ parseKeyboardContent(parser, selected ? skip : true);
+ } else {
+ // Processing Keys.
+ parseRowContent(parser, row, selected ? skip : true);
+ }
+ return selected;
+ }
+
+ private boolean parseCaseCondition(final XmlPullParser parser) {
+ final KeyboardId id = mParams.mId;
+ if (id == null) {
+ return true;
+ }
+ final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Case);
+ try {
+ final boolean keyboardLayoutSetElementMatched = matchTypedValue(a,
+ R.styleable.Keyboard_Case_keyboardLayoutSetElement, id.mElementId,
+ KeyboardId.elementIdToName(id.mElementId));
+ final boolean modeMatched = matchTypedValue(a,
+ R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode));
+ final boolean navigateNextMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_navigateNext, id.navigateNext());
+ final boolean navigatePreviousMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_navigatePrevious, id.navigatePrevious());
+ final boolean passwordInputMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_passwordInput, id.passwordInput());
+ final boolean clobberSettingsKeyMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey);
+ final boolean shortcutKeyEnabledMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled);
+ final boolean hasShortcutKeyMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey);
+ final boolean languageSwitchKeyEnabledMatched = matchBoolean(a,
+ R.styleable.Keyboard_Case_languageSwitchKeyEnabled,
+ id.mLanguageSwitchKeyEnabled);
+ 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,
+ R.styleable.Keyboard_Case_localeCode, id.mLocale.toString());
+ final boolean languageCodeMatched = matchString(a,
+ R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
+ final boolean countryCodeMatched = matchString(a,
+ R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
+ final boolean selected = keyboardLayoutSetElementMatched && modeMatched
+ && navigateNextMatched && navigatePreviousMatched && passwordInputMatched
+ && clobberSettingsKeyMatched && shortcutKeyEnabledMatched
+ && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched
+ && 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_keyboardLayoutSetElement),
+ "keyboardLayoutSetElement"),
+ textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"),
+ textAttr(a.getString(R.styleable.Keyboard_Case_imeAction),
+ "imeAction"),
+ booleanAttr(a, R.styleable.Keyboard_Case_navigateNext,
+ "navigateNext"),
+ booleanAttr(a, R.styleable.Keyboard_Case_navigatePrevious,
+ "navigatePrevious"),
+ booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey,
+ "clobberSettingsKey"),
+ booleanAttr(a, R.styleable.Keyboard_Case_passwordInput,
+ "passwordInput"),
+ booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled,
+ "shortcutKeyEnabled"),
+ booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey,
+ "hasShortcutKey"),
+ booleanAttr(a, R.styleable.Keyboard_Case_languageSwitchKeyEnabled,
+ "languageSwitchKeyEnabled"),
+ booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine,
+ "isMultiLine"),
+ 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 {
+ a.recycle();
+ }
+ }
+
+ private static boolean matchInteger(final TypedArray a, final int index, final int value) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for
+ // the attribute.
+ return !a.hasValue(index) || a.getInt(index, 0) == value;
+ }
+
+ private static boolean matchBoolean(final TypedArray a, final int index, final boolean value) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for
+ // the attribute.
+ return !a.hasValue(index) || a.getBoolean(index, false) == value;
+ }
+
+ private static boolean matchString(final TypedArray a, final int index, final String value) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for
+ // the attribute.
+ return !a.hasValue(index)
+ || StringUtils.containsInArray(value, a.getString(index).split("\\|"));
+ }
+
+ private static boolean matchTypedValue(final TypedArray a, final int index, final int intValue,
+ final String strValue) {
+ // If <case> does not have "index" attribute, that means this <case> is wild-card for
+ // the attribute.
+ final TypedValue v = a.peekValue(index);
+ if (v == null) {
+ return true;
+ }
+ if (ResourceUtils.isIntegerValue(v)) {
+ return intValue == a.getInt(index, 0);
+ } else if (ResourceUtils.isStringValue(v)) {
+ return StringUtils.containsInArray(strValue, a.getString(index).split("\\|"));
+ }
+ return false;
+ }
+
+ private boolean parseDefault(final XmlPullParser parser, final KeyboardRow row,
+ final boolean skip) throws XmlPullParserException, IOException {
+ if (DEBUG) startTag("<%s>", TAG_DEFAULT);
+ if (row == null) {
+ parseKeyboardContent(parser, skip);
+ } else {
+ parseRowContent(parser, row, skip);
+ }
+ return true;
+ }
+
+ private void parseKeyStyle(final XmlPullParser parser, final boolean skip)
+ throws XmlPullParserException, IOException {
+ TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_KeyStyle);
+ TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Key);
+ try {
+ 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) {
+ mParams.mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
+ }
+ } finally {
+ keyStyleAttr.recycle();
+ keyAttrs.recycle();
+ }
+ XmlParseUtils.checkEndTag(TAG_KEY_STYLE, parser);
+ }
+
+ private void startKeyboard() {
+ mCurrentY += mParams.mTopPadding;
+ mTopEdge = true;
+ }
+
+ private void startRow(final KeyboardRow row) {
+ addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
+ mCurrentRow = row;
+ mLeftEdge = true;
+ mRightEdgeKey = null;
+ }
+
+ private void endRow(final KeyboardRow row) {
+ if (mCurrentRow == null) {
+ throw new InflateException("orphan end row tag");
+ }
+ if (mRightEdgeKey != null) {
+ mRightEdgeKey.markAsRightEdge(mParams);
+ mRightEdgeKey = null;
+ }
+ addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
+ mCurrentY += row.mRowHeight;
+ mCurrentRow = null;
+ mTopEdge = false;
+ }
+
+ private void endKey(final Key key) {
+ mParams.onAddKey(key);
+ if (mLeftEdge) {
+ key.markAsLeftEdge(mParams);
+ mLeftEdge = false;
+ }
+ if (mTopEdge) {
+ key.markAsTopEdge(mParams);
+ }
+ mRightEdgeKey = key;
+ }
+
+ private void endKeyboard() {
+ // nothing to do here.
+ }
+
+ private void addEdgeSpace(final float width, final KeyboardRow row) {
+ row.advanceXPos(width);
+ mLeftEdge = false;
+ mRightEdgeKey = null;
+ }
+
+ private static String textAttr(final String value, final String name) {
+ return value != null ? String.format(" %s=%s", name, value) : "";
+ }
+
+ private static String booleanAttr(final TypedArray a, final int index, final String name) {
+ return a.hasValue(index)
+ ? String.format(" %s=%s", name, a.getBoolean(index, false)) : "";
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
new file mode 100644
index 000000000..ff5d31528
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.graphics.Typeface;
+import android.util.SparseIntArray;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.ResourceUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+public class KeyboardParams {
+ public KeyboardId mId;
+ public int mThemeId;
+
+ /** Total height and width of the keyboard, including the paddings and keys */
+ public int mOccupiedHeight;
+ public int mOccupiedWidth;
+
+ /** Base height and width of the keyboard used to calculate rows' or keys' heights and
+ * widths
+ */
+ public int mBaseHeight;
+ public int mBaseWidth;
+
+ public int mTopPadding;
+ public int mBottomPadding;
+ public int mHorizontalEdgesPadding;
+ public int mHorizontalCenterPadding;
+
+ public Typeface mKeyTypeface = null;
+ public float mKeyLetterRatio = ResourceUtils.UNDEFINED_RATIO;
+ public int mKeyLetterSize = ResourceUtils.UNDEFINED_DIMENSION;
+ public float mKeyHintLetterRatio = ResourceUtils.UNDEFINED_RATIO;
+ public float mKeyShiftedLetterHintRatio = ResourceUtils.UNDEFINED_RATIO;
+
+ public int mDefaultRowHeight;
+ public int mDefaultKeyWidth;
+ public int mHorizontalGap;
+ public int mVerticalGap;
+
+ public int mMoreKeysTemplate;
+ public int mMaxMoreKeysKeyboardColumn;
+
+ public int GRID_WIDTH;
+ public int GRID_HEIGHT;
+
+ public final HashSet<Key> mKeys = CollectionUtils.newHashSet();
+ public final ArrayList<Key> mShiftKeys = CollectionUtils.newArrayList();
+ public final ArrayList<Key> mAltCodeKeysWhileTyping = CollectionUtils.newArrayList();
+ public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
+ public final KeyboardCodesSet mCodesSet = new KeyboardCodesSet();
+ public final KeyboardTextsSet mTextsSet = new KeyboardTextsSet();
+ public final KeyStylesSet mKeyStyles = new KeyStylesSet(mTextsSet);
+
+ public KeysCache mKeysCache;
+
+ public int mMostCommonKeyHeight = 0;
+ public int mMostCommonKeyWidth = 0;
+
+ public boolean mProximityCharsCorrectionEnabled;
+
+ public final TouchPositionCorrection mTouchPositionCorrection =
+ new TouchPositionCorrection();
+
+ protected void clearKeys() {
+ mKeys.clear();
+ mShiftKeys.clear();
+ clearHistogram();
+ }
+
+ public void onAddKey(final Key newKey) {
+ final Key key = (mKeysCache != null) ? mKeysCache.get(newKey) : newKey;
+ final boolean zeroWidthSpacer = key.isSpacer() && key.mWidth == 0;
+ if (!zeroWidthSpacer) {
+ mKeys.add(key);
+ updateHistogram(key);
+ }
+ if (key.mCode == Keyboard.CODE_SHIFT) {
+ mShiftKeys.add(key);
+ }
+ if (key.altCodeWhileTyping()) {
+ mAltCodeKeysWhileTyping.add(key);
+ }
+ }
+
+ private int mMaxHeightCount = 0;
+ private int mMaxWidthCount = 0;
+ private final SparseIntArray mHeightHistogram = new SparseIntArray();
+ private final SparseIntArray mWidthHistogram = new SparseIntArray();
+
+ private void clearHistogram() {
+ mMostCommonKeyHeight = 0;
+ mMaxHeightCount = 0;
+ mHeightHistogram.clear();
+
+ mMaxWidthCount = 0;
+ mMostCommonKeyWidth = 0;
+ mWidthHistogram.clear();
+ }
+
+ private static int updateHistogramCounter(final SparseIntArray histogram, final int key) {
+ final int index = histogram.indexOfKey(key);
+ final int count = (index >= 0 ? histogram.get(key) : 0) + 1;
+ histogram.put(key, count);
+ return count;
+ }
+
+ private void updateHistogram(final Key key) {
+ final int height = key.mHeight + mVerticalGap;
+ final int heightCount = updateHistogramCounter(mHeightHistogram, height);
+ if (heightCount > mMaxHeightCount) {
+ mMaxHeightCount = heightCount;
+ mMostCommonKeyHeight = height;
+ }
+
+ final int width = key.mWidth + mHorizontalGap;
+ final int widthCount = updateHistogramCounter(mWidthHistogram, width);
+ if (widthCount > mMaxWidthCount) {
+ mMaxWidthCount = widthCount;
+ mMostCommonKeyWidth = width;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java
new file mode 100644
index 000000000..eb17b0ea4
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.Xml;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResourceUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
+ * Some of the key size defaults can be overridden per row from what the {@link Keyboard}
+ * defines.
+ */
+public class KeyboardRow {
+ // keyWidth enum constants
+ private static final int KEYWIDTH_NOT_ENUM = 0;
+ private static final int KEYWIDTH_FILL_RIGHT = -1;
+
+ private final KeyboardParams mParams;
+ /** Default width of a key in this row. */
+ private float mDefaultKeyWidth;
+ /** Default height of a key in this row. */
+ public final int mRowHeight;
+ /** Default keyLabelFlags in this row. */
+ private int mDefaultKeyLabelFlags;
+ /** Default backgroundType for this row */
+ private int mDefaultBackgroundType;
+
+ private final int mCurrentY;
+ // Will be updated by {@link Key}'s constructor.
+ private float mCurrentX;
+
+ public KeyboardRow(final Resources res, final KeyboardParams params, final XmlPullParser parser,
+ final int y) {
+ mParams = params;
+ TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard);
+ mRowHeight = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr,
+ R.styleable.Keyboard_rowHeight,
+ params.mBaseHeight, params.mDefaultRowHeight);
+ keyboardAttr.recycle();
+ TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.Keyboard_Key);
+ mDefaultKeyWidth = ResourceUtils.getDimensionOrFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth,
+ params.mBaseWidth, params.mDefaultKeyWidth);
+ mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType,
+ Key.BACKGROUND_TYPE_NORMAL);
+ keyAttr.recycle();
+
+ // TODO: Initialize this with <Row> attribute as backgroundType is done.
+ mDefaultKeyLabelFlags = 0;
+ mCurrentY = y;
+ mCurrentX = 0.0f;
+ }
+
+ public float getDefaultKeyWidth() {
+ return mDefaultKeyWidth;
+ }
+
+ public void setDefaultKeyWidth(final float defaultKeyWidth) {
+ mDefaultKeyWidth = defaultKeyWidth;
+ }
+
+ public int getDefaultKeyLabelFlags() {
+ return mDefaultKeyLabelFlags;
+ }
+
+ public void setDefaultKeyLabelFlags(final int keyLabelFlags) {
+ mDefaultKeyLabelFlags = keyLabelFlags;
+ }
+
+ public int getDefaultBackgroundType() {
+ return mDefaultBackgroundType;
+ }
+
+ public void setDefaultBackgroundType(final int backgroundType) {
+ mDefaultBackgroundType = backgroundType;
+ }
+
+ public void setXPos(final float keyXPos) {
+ mCurrentX = keyXPos;
+ }
+
+ public void advanceXPos(final float width) {
+ mCurrentX += width;
+ }
+
+ public int getKeyY() {
+ return mCurrentY;
+ }
+
+ public float getKeyX(final TypedArray keyAttr) {
+ final int keyboardRightEdge = mParams.mOccupiedWidth
+ - mParams.mHorizontalEdgesPadding;
+ if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
+ final float keyXPos = ResourceUtils.getDimensionOrFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0);
+ if (keyXPos < 0) {
+ // If keyXPos is negative, the actual x-coordinate will be
+ // keyboardWidth + keyXPos.
+ // keyXPos shouldn't be less than mCurrentX because drawable area for this
+ // key starts at mCurrentX. Or, this key will overlaps the adjacent key on
+ // its left hand side.
+ return Math.max(keyXPos + keyboardRightEdge, mCurrentX);
+ } else {
+ return keyXPos + mParams.mHorizontalEdgesPadding;
+ }
+ }
+ return mCurrentX;
+ }
+
+ public float getKeyWidth(final TypedArray keyAttr) {
+ return getKeyWidth(keyAttr, mCurrentX);
+ }
+
+ public float getKeyWidth(final TypedArray keyAttr, final float keyXPos) {
+ final int widthType = ResourceUtils.getEnumValue(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
+ switch (widthType) {
+ case KEYWIDTH_FILL_RIGHT:
+ final int keyboardRightEdge =
+ mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding;
+ // If keyWidth is fillRight, the actual key width will be determined to fill
+ // out the area up to the right edge of the keyboard.
+ return keyboardRightEdge - keyXPos;
+ default: // KEYWIDTH_NOT_ENUM
+ return ResourceUtils.getDimensionOrFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyWidth,
+ mParams.mBaseWidth, mDefaultKeyWidth);
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeysCache.java b/java/src/com/android/inputmethod/keyboard/internal/KeysCache.java
new file mode 100644
index 000000000..f54617c98
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeysCache.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.latin.CollectionUtils;
+
+import java.util.HashMap;
+
+public class KeysCache {
+ private final HashMap<Key, Key> mMap = CollectionUtils.newHashMap();
+
+ public void clear() {
+ mMap.clear();
+ }
+
+ public Key get(final Key key) {
+ final Key existingKey = mMap.get(key);
+ if (existingKey != null) {
+ // Reuse the existing element that equals to "key" without adding "key" to the map.
+ return existingKey;
+ }
+ mMap.put(key, key);
+ return key;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
new file mode 100644
index 000000000..5da26543f
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.StringUtils;
+
+import java.util.Locale;
+
+public class MoreKeySpec {
+ public final int mCode;
+ public final String mLabel;
+ public final String mOutputText;
+ public final int mIconId;
+
+ public MoreKeySpec(final String moreKeySpec, boolean needsToUpperCase, final Locale locale,
+ final KeyboardCodesSet codesSet) {
+ mLabel = KeySpecParser.toUpperCaseOfStringForLocale(
+ KeySpecParser.getLabel(moreKeySpec), needsToUpperCase, locale);
+ final int code = KeySpecParser.toUpperCaseOfCodeForLocale(
+ KeySpecParser.getCode(moreKeySpec, codesSet), needsToUpperCase, locale);
+ if (code == Keyboard.CODE_UNSPECIFIED) {
+ // Some letter, for example German Eszett (U+00DF: "ß"), has multiple characters
+ // upper case representation ("SS").
+ mCode = Keyboard.CODE_OUTPUT_TEXT;
+ mOutputText = mLabel;
+ } else {
+ mCode = code;
+ mOutputText = KeySpecParser.toUpperCaseOfStringForLocale(
+ KeySpecParser.getOutputText(moreKeySpec), needsToUpperCase, locale);
+ }
+ mIconId = KeySpecParser.getIconId(moreKeySpec);
+ }
+
+ @Override
+ public String toString() {
+ final String label = (mIconId == KeyboardIconsSet.ICON_UNDEFINED ? mLabel
+ : KeySpecParser.PREFIX_ICON + KeyboardIconsSet.getIconName(mIconId));
+ final String output = (mCode == Keyboard.CODE_OUTPUT_TEXT ? mOutputText
+ : Keyboard.printableCode(mCode));
+ if (StringUtils.codePointCount(label) == 1 && label.codePointAt(0) == mCode) {
+ return output;
+ } else {
+ return label + "|" + output;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java b/java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java
new file mode 100644
index 000000000..69dc01cd6
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/TouchPositionCorrection.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import com.android.inputmethod.latin.LatinImeLogger;
+
+public class TouchPositionCorrection {
+ private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3;
+
+ public boolean mEnabled;
+ public float[] mXs;
+ public float[] mYs;
+ public float[] mRadii;
+
+ public void load(final String[] data) {
+ final int dataLength = data.length;
+ if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
+ if (LatinImeLogger.sDBG) {
+ throw new RuntimeException(
+ "the size of touch position correction data is invalid");
+ }
+ return;
+ }
+
+ final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+ mXs = new float[length];
+ mYs = new float[length];
+ mRadii = new float[length];
+ try {
+ for (int i = 0; i < dataLength; ++i) {
+ final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+ final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
+ final float value = Float.parseFloat(data[i]);
+ if (type == 0) {
+ mXs[index] = value;
+ } else if (type == 1) {
+ mYs[index] = value;
+ } else {
+ mRadii[index] = value;
+ }
+ }
+ } catch (NumberFormatException e) {
+ if (LatinImeLogger.sDBG) {
+ throw new RuntimeException(
+ "the number format for touch position correction data is invalid");
+ }
+ mXs = null;
+ mYs = null;
+ mRadii = null;
+ }
+ }
+
+ // TODO: Remove this method.
+ public void setEnabled(final boolean enabled) {
+ mEnabled = enabled;
+ }
+
+ public boolean isValid() {
+ return mEnabled && mXs != null && mYs != null && mRadii != null
+ && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/ResourceUtils.java b/java/src/com/android/inputmethod/latin/ResourceUtils.java
index e01ac3dd4..5021ad384 100644
--- a/java/src/com/android/inputmethod/latin/ResourceUtils.java
+++ b/java/src/com/android/inputmethod/latin/ResourceUtils.java
@@ -17,11 +17,16 @@
package com.android.inputmethod.latin;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.os.Build;
+import android.util.TypedValue;
import java.util.HashMap;
public final class ResourceUtils {
+ public static final float UNDEFINED_RATIO = -1.0f;
+ public static final int UNDEFINED_DIMENSION = -1;
+
private ResourceUtils() {
// This utility class is not publicly instantiable.
}
@@ -45,4 +50,79 @@ public final class ResourceUtils {
}
return sDeviceOverrideValueMap.get(key);
}
+
+ public static boolean isValidFraction(final float fraction) {
+ return fraction >= 0.0f;
+ }
+
+ // {@link Resources#getDimensionPixelSize(int)} returns at least one pixel size.
+ public static boolean isValidDimensionPixelSize(final int dimension) {
+ return dimension > 0;
+ }
+
+ // {@link Resources#getDimensionPixelOffset(int)} may return zero pixel offset.
+ public static boolean isValidDimensionPixelOffset(final int dimension) {
+ return dimension >= 0;
+ }
+
+ public static float getFraction(final TypedArray a, final int index, final float defValue) {
+ final TypedValue value = a.peekValue(index);
+ if (value == null || !isFractionValue(value)) {
+ return defValue;
+ }
+ return a.getFraction(index, 1, 1, defValue);
+ }
+
+ public static float getFraction(final TypedArray a, final int index) {
+ return getFraction(a, index, UNDEFINED_RATIO);
+ }
+
+ public static int getDimensionPixelSize(final TypedArray a, final int index) {
+ final TypedValue value = a.peekValue(index);
+ if (value == null || !isDimensionValue(value)) {
+ return ResourceUtils.UNDEFINED_DIMENSION;
+ }
+ return a.getDimensionPixelSize(index, ResourceUtils.UNDEFINED_DIMENSION);
+ }
+
+ public static float getDimensionOrFraction(TypedArray a, int index, int base,
+ float defValue) {
+ final TypedValue value = a.peekValue(index);
+ if (value == null) {
+ return defValue;
+ }
+ if (isFractionValue(value)) {
+ return a.getFraction(index, base, base, defValue);
+ } else if (isDimensionValue(value)) {
+ return a.getDimension(index, defValue);
+ }
+ return defValue;
+ }
+
+ public static int getEnumValue(TypedArray a, int index, int defValue) {
+ final TypedValue value = a.peekValue(index);
+ if (value == null) {
+ return defValue;
+ }
+ if (isIntegerValue(value)) {
+ return a.getInt(index, defValue);
+ }
+ return defValue;
+ }
+
+ public static boolean isFractionValue(TypedValue v) {
+ return v.type == TypedValue.TYPE_FRACTION;
+ }
+
+ public static boolean isDimensionValue(TypedValue v) {
+ return v.type == TypedValue.TYPE_DIMENSION;
+ }
+
+ public static boolean isIntegerValue(TypedValue v) {
+ return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT;
+ }
+
+ public static boolean isStringValue(TypedValue v) {
+ return v.type == TypedValue.TYPE_STRING;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index 161b94ca0..d4f7cab5c 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -188,6 +188,54 @@ public class BinaryDictInputOutput {
// suspicion that a bug might be causing an infinite loop.
private static final int MAX_PASSES = 24;
+ private interface FusionDictionaryBufferInterface {
+ public int readUnsignedByte();
+ public int readUnsignedShort();
+ public int readUnsignedInt24();
+ public int readInt();
+ public int position();
+ public void position(int newPosition);
+ }
+
+ private static final class ByteBufferWrapper implements FusionDictionaryBufferInterface {
+ private ByteBuffer buffer;
+ ByteBufferWrapper(final ByteBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ @Override
+ public int readUnsignedByte() {
+ return ((int)buffer.get()) & 0xFF;
+ }
+
+ @Override
+ public int readUnsignedShort() {
+ return ((int)buffer.getShort()) & 0xFFFF;
+ }
+
+ @Override
+ public int readUnsignedInt24() {
+ final int retval = readUnsignedByte();
+ return (retval << 16) + readUnsignedShort();
+ }
+
+ @Override
+ public int readInt() {
+ return buffer.getInt();
+ }
+
+ @Override
+ public int position() {
+ return buffer.position();
+ }
+
+ @Override
+ public void position(int newPos) {
+ buffer.position(newPos);
+ return;
+ }
+ }
+
/**
* A class grouping utility function for our specific character encoding.
*/
@@ -310,9 +358,9 @@ public class BinaryDictInputOutput {
}
/**
- * Reads a string from a ByteBuffer. This is the converse of the above method.
+ * Reads a string from a buffer. This is the converse of the above method.
*/
- private static String readString(final ByteBuffer buffer) {
+ private static String readString(final FusionDictionaryBufferInterface buffer) {
final StringBuilder s = new StringBuilder();
int character = readChar(buffer);
while (character != INVALID_CHARACTER) {
@@ -323,19 +371,19 @@ public class BinaryDictInputOutput {
}
/**
- * Reads a character from the ByteBuffer.
+ * Reads a character from the buffer.
*
* This follows the character format documented earlier in this source file.
*
* @param buffer the buffer, positioned over an encoded character.
* @return the character code.
*/
- private static int readChar(final ByteBuffer buffer) {
- int character = readUnsignedByte(buffer);
+ private static int readChar(final FusionDictionaryBufferInterface buffer) {
+ int character = buffer.readUnsignedByte();
if (!fitsOnOneByte(character)) {
if (GROUP_CHARACTERS_TERMINATOR == character) return INVALID_CHARACTER;
character <<= 16;
- character += readUnsignedShort(buffer);
+ character += buffer.readUnsignedShort();
}
return character;
}
@@ -1093,10 +1141,10 @@ public class BinaryDictInputOutput {
// readDictionaryBinary is the public entry point for them.
static final int[] characterBuffer = new int[MAX_WORD_LENGTH];
- private static CharGroupInfo readCharGroup(final ByteBuffer buffer,
+ private static CharGroupInfo readCharGroup(final FusionDictionaryBufferInterface buffer,
final int originalGroupAddress) {
int addressPointer = originalGroupAddress;
- final int flags = readUnsignedByte(buffer);
+ final int flags = buffer.readUnsignedByte();
++addressPointer;
final int characters[];
if (0 != (flags & FLAG_HAS_MULTIPLE_CHARS)) {
@@ -1117,22 +1165,22 @@ public class BinaryDictInputOutput {
final int frequency;
if (0 != (FLAG_IS_TERMINAL & flags)) {
++addressPointer;
- frequency = readUnsignedByte(buffer);
+ frequency = buffer.readUnsignedByte();
} else {
frequency = CharGroup.NOT_A_TERMINAL;
}
int childrenAddress = addressPointer;
switch (flags & MASK_GROUP_ADDRESS_TYPE) {
case FLAG_GROUP_ADDRESS_TYPE_ONEBYTE:
- childrenAddress += readUnsignedByte(buffer);
+ childrenAddress += buffer.readUnsignedByte();
addressPointer += 1;
break;
case FLAG_GROUP_ADDRESS_TYPE_TWOBYTES:
- childrenAddress += readUnsignedShort(buffer);
+ childrenAddress += buffer.readUnsignedShort();
addressPointer += 2;
break;
case FLAG_GROUP_ADDRESS_TYPE_THREEBYTES:
- childrenAddress += readUnsignedInt24(buffer);
+ childrenAddress += buffer.readUnsignedInt24();
addressPointer += 3;
break;
case FLAG_GROUP_ADDRESS_TYPE_NOADDRESS:
@@ -1144,9 +1192,9 @@ public class BinaryDictInputOutput {
if (0 != (flags & FLAG_HAS_SHORTCUT_TARGETS)) {
final int pointerBefore = buffer.position();
shortcutTargets = new ArrayList<WeightedString>();
- buffer.getShort(); // Skip the size
+ buffer.readUnsignedShort(); // Skip the size
while (true) {
- final int targetFlags = readUnsignedByte(buffer);
+ final int targetFlags = buffer.readUnsignedByte();
final String word = CharEncoding.readString(buffer);
shortcutTargets.add(new WeightedString(word,
targetFlags & FLAG_ATTRIBUTE_FREQUENCY));
@@ -1158,22 +1206,22 @@ public class BinaryDictInputOutput {
if (0 != (flags & FLAG_HAS_BIGRAMS)) {
bigrams = new ArrayList<PendingAttribute>();
while (true) {
- final int bigramFlags = readUnsignedByte(buffer);
+ final int bigramFlags = buffer.readUnsignedByte();
++addressPointer;
final int sign = 0 == (bigramFlags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) ? 1 : -1;
int bigramAddress = addressPointer;
switch (bigramFlags & MASK_ATTRIBUTE_ADDRESS_TYPE) {
case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
- bigramAddress += sign * readUnsignedByte(buffer);
+ bigramAddress += sign * buffer.readUnsignedByte();
addressPointer += 1;
break;
case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
- bigramAddress += sign * readUnsignedShort(buffer);
+ bigramAddress += sign * buffer.readUnsignedShort();
addressPointer += 2;
break;
case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
- final int offset = (readUnsignedByte(buffer) << 16)
- + readUnsignedShort(buffer);
+ final int offset = (buffer.readUnsignedByte() << 16)
+ + buffer.readUnsignedShort();
bigramAddress += sign * offset;
addressPointer += 3;
break;
@@ -1192,13 +1240,13 @@ public class BinaryDictInputOutput {
/**
* Reads and returns the char group count out of a buffer and forwards the pointer.
*/
- private static int readCharGroupCount(final ByteBuffer buffer) {
- final int msb = readUnsignedByte(buffer);
+ private static int readCharGroupCount(final FusionDictionaryBufferInterface buffer) {
+ final int msb = buffer.readUnsignedByte();
if (MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= msb) {
return msb;
} else {
return ((MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT & msb) << 8)
- + readUnsignedByte(buffer);
+ + buffer.readUnsignedByte();
}
}
@@ -1215,8 +1263,8 @@ public class BinaryDictInputOutput {
* @param address the address to seek.
* @return the word, as a string.
*/
- private static String getWordAtAddress(final ByteBuffer buffer, final int headerSize,
- final int address) {
+ private static String getWordAtAddress(final FusionDictionaryBufferInterface buffer,
+ final int headerSize, final int address) {
final String cachedString = wordCache.get(address);
if (null != cachedString) return cachedString;
final int originalPointer = buffer.position();
@@ -1241,7 +1289,7 @@ public class BinaryDictInputOutput {
builder.append(new String(last.mCharacters, 0, last.mCharacters.length));
buffer.position(last.mChildrenAddress + headerSize);
groupOffset = last.mChildrenAddress + 1;
- i = readUnsignedByte(buffer);
+ i = buffer.readUnsignedByte();
last = null;
continue;
}
@@ -1251,7 +1299,7 @@ public class BinaryDictInputOutput {
builder.append(new String(last.mCharacters, 0, last.mCharacters.length));
buffer.position(last.mChildrenAddress + headerSize);
groupOffset = last.mChildrenAddress + 1;
- i = readUnsignedByte(buffer);
+ i = buffer.readUnsignedByte();
last = null;
continue;
}
@@ -1262,10 +1310,10 @@ public class BinaryDictInputOutput {
}
/**
- * Reads a single node from a binary file.
+ * Reads a single node from a buffer.
*
- * This methods reads the file at the current position of its file pointer. A node is
- * fully expected to start at the current position.
+ * This methods reads the file at the current position. A node is fully expected to start at
+ * the current position.
* This will recursively read other nodes into the structure, populating the reverse
* maps on the fly and using them to keep track of already read nodes.
*
@@ -1275,7 +1323,7 @@ public class BinaryDictInputOutput {
* @param reverseGroupMap a mapping from addresses to already read character groups.
* @return the read node with all his children already read.
*/
- private static Node readNode(final ByteBuffer buffer, final int headerSize,
+ private static Node readNode(final FusionDictionaryBufferInterface buffer, final int headerSize,
final Map<Integer, Node> reverseNodeMap, final Map<Integer, CharGroup> reverseGroupMap)
throws IOException {
final int nodeOrigin = buffer.position() - headerSize;
@@ -1283,7 +1331,7 @@ public class BinaryDictInputOutput {
final ArrayList<CharGroup> nodeContents = new ArrayList<CharGroup>();
int groupOffset = nodeOrigin + getGroupCountSize(count);
for (int i = count; i > 0; --i) {
- CharGroupInfo info =readCharGroup(buffer, groupOffset);
+ CharGroupInfo info = readCharGroup(buffer, groupOffset);
ArrayList<WeightedString> shortcutTargets = info.mShortcutTargets;
ArrayList<WeightedString> bigrams = null;
if (null != info.mBigrams) {
@@ -1323,69 +1371,101 @@ public class BinaryDictInputOutput {
* Helper function to get the binary format version from the header.
* @throws IOException
*/
- private static int getFormatVersion(final ByteBuffer buffer) throws IOException {
- final int magic_v1 = readUnsignedShort(buffer);
- if (VERSION_1_MAGIC_NUMBER == magic_v1) return readUnsignedByte(buffer);
- final int magic_v2 = (magic_v1 << 16) + readUnsignedShort(buffer);
- if (VERSION_2_MAGIC_NUMBER == magic_v2) return readUnsignedShort(buffer);
+ private static int getFormatVersion(final FusionDictionaryBufferInterface buffer)
+ throws IOException {
+ final int magic_v1 = buffer.readUnsignedShort();
+ if (VERSION_1_MAGIC_NUMBER == magic_v1) return buffer.readUnsignedByte();
+ final int magic_v2 = (magic_v1 << 16) + buffer.readUnsignedShort();
+ if (VERSION_2_MAGIC_NUMBER == magic_v2) return buffer.readUnsignedShort();
return NOT_A_VERSION_NUMBER;
}
/**
- * Reads options from a file and populate a map with their contents.
+ * Helper function to get and validate the binary format version.
+ * @throws UnsupportedFormatException
+ * @throws IOException
+ */
+ private static int checkFormatVersion(final FusionDictionaryBufferInterface buffer)
+ throws IOException, UnsupportedFormatException {
+ final int version = getFormatVersion(buffer);
+ if (version < MINIMUM_SUPPORTED_VERSION || version > MAXIMUM_SUPPORTED_VERSION) {
+ throw new UnsupportedFormatException("This file has version " + version
+ + ", but this implementation does not support versions above "
+ + MAXIMUM_SUPPORTED_VERSION);
+ }
+ return version;
+ }
+
+ /**
+ * Reads a header from a buffer.
+ * @throws IOException
+ * @throws UnsupportedFormatException
+ */
+ private static int readHeader(final FusionDictionaryBufferInterface buffer,
+ final HashMap<String, String> options,
+ final int version)
+ throws IOException, UnsupportedFormatException {
+
+ final int headerSize;
+ if (version < FIRST_VERSION_WITH_HEADER_SIZE) {
+ headerSize = buffer.position();
+ } else {
+ headerSize = buffer.readInt();
+ populateOptions(buffer, headerSize, options);
+ buffer.position(headerSize);
+ }
+
+ if (headerSize < 0) {
+ throw new UnsupportedFormatException("header size can't be negative.");
+ }
+
+ return headerSize;
+ }
+
+ /**
+ * Reads options from a buffer and populate a map with their contents.
*
- * The file is read at the current file pointer, so the caller must take care the pointer
+ * The buffer is read at the current position, so the caller must take care the pointer
* is in the right place before calling this.
*/
- public static void populateOptions(final ByteBuffer buffer, final int headerSize,
- final HashMap<String, String> options) {
+ public static void populateOptions(final FusionDictionaryBufferInterface buffer,
+ final int headerSize, final HashMap<String, String> options) {
while (buffer.position() < headerSize) {
final String key = CharEncoding.readString(buffer);
final String value = CharEncoding.readString(buffer);
options.put(key, value);
}
}
+ // TODO: remove this method.
+ public static void populateOptions(final ByteBuffer buffer, final int headerSize,
+ final HashMap<String, String> options) {
+ populateOptions(new ByteBufferWrapper(buffer), headerSize, options);
+ }
/**
- * Reads a byte buffer and returns the memory representation of the dictionary.
+ * Reads a buffer and returns the memory representation of the dictionary.
*
- * This high-level method takes a binary file and reads its contents, populating a
+ * This high-level method takes a buffer and reads its contents, populating a
* FusionDictionary structure. The optional dict argument is an existing dictionary to
- * which words from the file should be added. If it is null, a new dictionary is created.
+ * which words from the buffer should be added. If it is null, a new dictionary is created.
*
* @param buffer the buffer to read.
* @param dict an optional dictionary to add words to, or null.
* @return the created (or merged) dictionary.
*/
- public static FusionDictionary readDictionaryBinary(final ByteBuffer buffer,
- final FusionDictionary dict) throws IOException, UnsupportedFormatException {
- // Check file version
- final int version = getFormatVersion(buffer);
- if (version < MINIMUM_SUPPORTED_VERSION || version > MAXIMUM_SUPPORTED_VERSION) {
- throw new UnsupportedFormatException("This file has version " + version
- + ", but this implementation does not support versions above "
- + MAXIMUM_SUPPORTED_VERSION);
- }
+ public static FusionDictionary readDictionaryBinary(
+ final FusionDictionaryBufferInterface buffer, final FusionDictionary dict)
+ throws IOException, UnsupportedFormatException {
// clear cache
wordCache.clear();
- // Read options
- final int optionsFlags = readUnsignedShort(buffer);
+ // Read header
+ final int version = checkFormatVersion(buffer);
+ final int optionsFlags = buffer.readUnsignedShort();
- final int headerSize;
final HashMap<String, String> options = new HashMap<String, String>();
- if (version < FIRST_VERSION_WITH_HEADER_SIZE) {
- headerSize = buffer.position();
- } else {
- headerSize = buffer.getInt();
- populateOptions(buffer, headerSize, options);
- buffer.position(headerSize);
- }
-
- if (headerSize < 0) {
- throw new UnsupportedFormatException("header size can't be negative.");
- }
+ final int headerSize = readHeader(buffer, options, version);
Map<Integer, Node> reverseNodeMapping = new TreeMap<Integer, Node>();
Map<Integer, CharGroup> reverseGroupMapping = new TreeMap<Integer, CharGroup>();
@@ -1413,26 +1493,10 @@ public class BinaryDictInputOutput {
return newDict;
}
- /**
- * Helper function to read one byte from ByteBuffer.
- */
- private static int readUnsignedByte(final ByteBuffer buffer) {
- return ((int)buffer.get()) & 0xFF;
- }
-
- /**
- * Helper function to read two byte from ByteBuffer.
- */
- private static int readUnsignedShort(final ByteBuffer buffer) {
- return ((int)buffer.getShort()) & 0xFFFF;
- }
-
- /**
- * Helper function to read three byte from ByteBuffer.
- */
- private static int readUnsignedInt24(final ByteBuffer buffer) {
- final int value = readUnsignedByte(buffer) << 16;
- return value + readUnsignedShort(buffer);
+ // TODO: remove this method.
+ public static FusionDictionary readDictionaryBinary(final ByteBuffer buffer,
+ final FusionDictionary dict) throws IOException, UnsupportedFormatException {
+ return readDictionaryBinary(new ByteBufferWrapper(buffer), dict);
}
/**
@@ -1450,7 +1514,7 @@ public class BinaryDictInputOutput {
inStream = new FileInputStream(file);
final ByteBuffer buffer = inStream.getChannel().map(
FileChannel.MapMode.READ_ONLY, 0, file.length());
- final int version = getFormatVersion(buffer);
+ final int version = getFormatVersion(new ByteBufferWrapper(buffer));
return (version >= MINIMUM_SUPPORTED_VERSION && version <= MAXIMUM_SUPPORTED_VERSION);
} catch (FileNotFoundException e) {
return false;
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 58b01aa55..1f883aa60 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -23,7 +23,9 @@ import android.graphics.drawable.Drawable;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.Utils;
@@ -31,145 +33,149 @@ import com.android.inputmethod.latin.Utils;
public class MoreSuggestions extends Keyboard {
public static final int SUGGESTION_CODE_BASE = 1024;
- MoreSuggestions(Builder.MoreSuggestionsParam params) {
+ MoreSuggestions(final MoreSuggestionsParam params) {
super(params);
}
- public static class Builder extends Keyboard.Builder<Builder.MoreSuggestionsParam> {
- private final MoreSuggestionsView mPaneView;
- private SuggestedWords mSuggestions;
- private int mFromPos;
- private int mToPos;
+ private static class MoreSuggestionsParam extends KeyboardParams {
+ private final int[] mWidths = new int[SuggestionStripView.MAX_SUGGESTIONS];
+ private final int[] mRowNumbers = new int[SuggestionStripView.MAX_SUGGESTIONS];
+ private final int[] mColumnOrders = new int[SuggestionStripView.MAX_SUGGESTIONS];
+ private final int[] mNumColumnsInRow = new int[SuggestionStripView.MAX_SUGGESTIONS];
+ private static final int MAX_COLUMNS_IN_ROW = 3;
+ private int mNumRows;
+ public Drawable mDivider;
+ public int mDividerWidth;
+
+ public MoreSuggestionsParam() {
+ super();
+ }
- public static class MoreSuggestionsParam extends Keyboard.Params {
- private final int[] mWidths = new int[SuggestionStripView.MAX_SUGGESTIONS];
- private final int[] mRowNumbers = new int[SuggestionStripView.MAX_SUGGESTIONS];
- private final int[] mColumnOrders = new int[SuggestionStripView.MAX_SUGGESTIONS];
- private final int[] mNumColumnsInRow = new int[SuggestionStripView.MAX_SUGGESTIONS];
- private static final int MAX_COLUMNS_IN_ROW = 3;
- private int mNumRows;
- public Drawable mDivider;
- public int mDividerWidth;
-
- public int layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth,
- int maxRow, MoreSuggestionsView view) {
- clearKeys();
- final Resources res = view.getContext().getResources();
- mDivider = res.getDrawable(R.drawable.more_suggestions_divider);
- mDividerWidth = mDivider.getIntrinsicWidth();
- final int padding = (int) res.getDimension(
- R.dimen.more_suggestions_key_horizontal_padding);
- final Paint paint = view.newDefaultLabelPaint();
-
- int row = 0;
- int pos = fromPos, rowStartPos = fromPos;
- final int size = Math.min(suggestions.size(), SuggestionStripView.MAX_SUGGESTIONS);
- while (pos < size) {
- final String word = suggestions.getWord(pos).toString();
- // TODO: Should take care of text x-scaling.
- mWidths[pos] = (int)view.getLabelWidth(word, paint) + padding;
- final int numColumn = pos - rowStartPos + 1;
- final int columnWidth =
- (maxWidth - mDividerWidth * (numColumn - 1)) / numColumn;
- if (numColumn > MAX_COLUMNS_IN_ROW
- || !fitInWidth(rowStartPos, pos + 1, columnWidth)) {
- if ((row + 1) >= maxRow) {
- break;
- }
- mNumColumnsInRow[row] = pos - rowStartPos;
- rowStartPos = pos;
- row++;
+ public int layout(final SuggestedWords suggestions, final int fromPos, final int maxWidth,
+ final int minWidth, final int maxRow, final MoreSuggestionsView view) {
+ clearKeys();
+ final Resources res = view.getContext().getResources();
+ mDivider = res.getDrawable(R.drawable.more_suggestions_divider);
+ mDividerWidth = mDivider.getIntrinsicWidth();
+ final int padding = (int) res.getDimension(
+ R.dimen.more_suggestions_key_horizontal_padding);
+ final Paint paint = view.newDefaultLabelPaint();
+
+ int row = 0;
+ int pos = fromPos, rowStartPos = fromPos;
+ final int size = Math.min(suggestions.size(), SuggestionStripView.MAX_SUGGESTIONS);
+ while (pos < size) {
+ final String word = suggestions.getWord(pos).toString();
+ // TODO: Should take care of text x-scaling.
+ mWidths[pos] = (int)view.getLabelWidth(word, paint) + padding;
+ final int numColumn = pos - rowStartPos + 1;
+ final int columnWidth =
+ (maxWidth - mDividerWidth * (numColumn - 1)) / numColumn;
+ if (numColumn > MAX_COLUMNS_IN_ROW
+ || !fitInWidth(rowStartPos, pos + 1, columnWidth)) {
+ if ((row + 1) >= maxRow) {
+ break;
}
- mColumnOrders[pos] = pos - rowStartPos;
- mRowNumbers[pos] = row;
- pos++;
+ mNumColumnsInRow[row] = pos - rowStartPos;
+ rowStartPos = pos;
+ row++;
}
- mNumColumnsInRow[row] = pos - rowStartPos;
- mNumRows = row + 1;
- mBaseWidth = mOccupiedWidth = Math.max(
- minWidth, calcurateMaxRowWidth(fromPos, pos));
- mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
- return pos - fromPos;
+ mColumnOrders[pos] = pos - rowStartPos;
+ mRowNumbers[pos] = row;
+ pos++;
}
+ mNumColumnsInRow[row] = pos - rowStartPos;
+ mNumRows = row + 1;
+ mBaseWidth = mOccupiedWidth = Math.max(
+ minWidth, calcurateMaxRowWidth(fromPos, pos));
+ mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
+ return pos - fromPos;
+ }
- private boolean fitInWidth(int startPos, int endPos, int width) {
- for (int pos = startPos; pos < endPos; pos++) {
- if (mWidths[pos] > width)
- return false;
- }
- return true;
+ private boolean fitInWidth(final int startPos, final int endPos, final int width) {
+ for (int pos = startPos; pos < endPos; pos++) {
+ if (mWidths[pos] > width)
+ return false;
}
+ return true;
+ }
- private int calcurateMaxRowWidth(int startPos, int endPos) {
- int maxRowWidth = 0;
- int pos = startPos;
- for (int row = 0; row < mNumRows; row++) {
- final int numColumnInRow = mNumColumnsInRow[row];
- int maxKeyWidth = 0;
- while (pos < endPos && mRowNumbers[pos] == row) {
- maxKeyWidth = Math.max(maxKeyWidth, mWidths[pos]);
- pos++;
- }
- maxRowWidth = Math.max(maxRowWidth,
- maxKeyWidth * numColumnInRow + mDividerWidth * (numColumnInRow - 1));
+ private int calcurateMaxRowWidth(final int startPos, final int endPos) {
+ int maxRowWidth = 0;
+ int pos = startPos;
+ for (int row = 0; row < mNumRows; row++) {
+ final int numColumnInRow = mNumColumnsInRow[row];
+ int maxKeyWidth = 0;
+ while (pos < endPos && mRowNumbers[pos] == row) {
+ maxKeyWidth = Math.max(maxKeyWidth, mWidths[pos]);
+ pos++;
}
- return maxRowWidth;
+ maxRowWidth = Math.max(maxRowWidth,
+ maxKeyWidth * numColumnInRow + mDividerWidth * (numColumnInRow - 1));
}
+ return maxRowWidth;
+ }
- private static final int[][] COLUMN_ORDER_TO_NUMBER = {
- { 0, },
- { 1, 0, },
- { 2, 0, 1},
- };
-
- public int getNumColumnInRow(int pos) {
- return mNumColumnsInRow[mRowNumbers[pos]];
- }
+ private static final int[][] COLUMN_ORDER_TO_NUMBER = {
+ { 0, },
+ { 1, 0, },
+ { 2, 0, 1},
+ };
- public int getColumnNumber(int pos) {
- final int columnOrder = mColumnOrders[pos];
- final int numColumn = getNumColumnInRow(pos);
- return COLUMN_ORDER_TO_NUMBER[numColumn - 1][columnOrder];
- }
+ public int getNumColumnInRow(final int pos) {
+ return mNumColumnsInRow[mRowNumbers[pos]];
+ }
- public int getX(int pos) {
- final int columnNumber = getColumnNumber(pos);
- return columnNumber * (getWidth(pos) + mDividerWidth);
- }
+ public int getColumnNumber(final int pos) {
+ final int columnOrder = mColumnOrders[pos];
+ final int numColumn = getNumColumnInRow(pos);
+ return COLUMN_ORDER_TO_NUMBER[numColumn - 1][columnOrder];
+ }
- public int getY(int pos) {
- final int row = mRowNumbers[pos];
- return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
- }
+ public int getX(final int pos) {
+ final int columnNumber = getColumnNumber(pos);
+ return columnNumber * (getWidth(pos) + mDividerWidth);
+ }
- public int getWidth(int pos) {
- final int numColumnInRow = getNumColumnInRow(pos);
- return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
- }
+ public int getY(final int pos) {
+ final int row = mRowNumbers[pos];
+ return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
+ }
- public void markAsEdgeKey(Key key, int pos) {
- final int row = mRowNumbers[pos];
- if (row == 0)
- key.markAsBottomEdge(this);
- if (row == mNumRows - 1)
- key.markAsTopEdge(this);
+ public int getWidth(final int pos) {
+ final int numColumnInRow = getNumColumnInRow(pos);
+ return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
+ }
- final int numColumnInRow = mNumColumnsInRow[row];
- final int column = getColumnNumber(pos);
- if (column == 0)
- key.markAsLeftEdge(this);
- if (column == numColumnInRow - 1)
- key.markAsRightEdge(this);
- }
+ public void markAsEdgeKey(final Key key, final int pos) {
+ final int row = mRowNumbers[pos];
+ if (row == 0)
+ key.markAsBottomEdge(this);
+ if (row == mNumRows - 1)
+ key.markAsTopEdge(this);
+
+ final int numColumnInRow = mNumColumnsInRow[row];
+ final int column = getColumnNumber(pos);
+ if (column == 0)
+ key.markAsLeftEdge(this);
+ if (column == numColumnInRow - 1)
+ key.markAsRightEdge(this);
}
+ }
- public Builder(MoreSuggestionsView paneView) {
+ public static class Builder extends KeyboardBuilder<MoreSuggestionsParam> {
+ private final MoreSuggestionsView mPaneView;
+ private SuggestedWords mSuggestions;
+ private int mFromPos;
+ private int mToPos;
+
+ public Builder(final MoreSuggestionsView paneView) {
super(paneView.getContext(), new MoreSuggestionsParam());
mPaneView = paneView;
}
- public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth,
- int minWidth, int maxRow) {
+ public Builder layout(final SuggestedWords suggestions, final int fromPos,
+ final int maxWidth, final int minWidth, final int maxRow) {
final Keyboard keyboard = KeyboardSwitcher.getInstance().getKeyboard();
final int xmlId = R.xml.kbd_suggestions_pane_template;
load(xmlId, keyboard.mId);
@@ -183,25 +189,6 @@ public class MoreSuggestions extends Keyboard {
return this;
}
- private static class Divider extends Key.Spacer {
- private final Drawable mIcon;
-
- public Divider(Keyboard.Params params, Drawable icon, int x, int y, int width,
- int height) {
- super(params, x, y, width, height);
- mIcon = icon;
- }
-
- @Override
- public Drawable getIcon(KeyboardIconsSet iconSet, int alpha) {
- // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
- // constructor.
- // TODO: Drawable itself should have an alpha value.
- mIcon.setAlpha(128);
- return mIcon;
- }
- }
-
@Override
public MoreSuggestions build() {
final MoreSuggestionsParam params = mParams;
@@ -228,4 +215,23 @@ public class MoreSuggestions extends Keyboard {
return new MoreSuggestions(params);
}
}
+
+ private static class Divider extends Key.Spacer {
+ private final Drawable mIcon;
+
+ public Divider(final KeyboardParams params, final Drawable icon, final int x,
+ final int y, final int width, final int height) {
+ super(params, x, y, width, height);
+ mIcon = icon;
+ }
+
+ @Override
+ public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
+ // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
+ // constructor.
+ // TODO: Drawable itself should have an alpha value.
+ mIcon.setAlpha(128);
+ return mIcon;
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 03263d274..9e8ab81b0 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -61,6 +61,7 @@ import com.android.inputmethod.latin.AutoCorrection;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResourceUtils;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.Utils;
@@ -196,15 +197,15 @@ public class SuggestionStripView extends RelativeLayout implements OnClickListen
R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripViewStyle);
mSuggestionStripOption = a.getInt(
R.styleable.SuggestionStripView_suggestionStripOption, 0);
- final float alphaValidTypedWord = getFraction(a,
+ final float alphaValidTypedWord = ResourceUtils.getFraction(a,
R.styleable.SuggestionStripView_alphaValidTypedWord, 1.0f);
- final float alphaTypedWord = getFraction(a,
+ final float alphaTypedWord = ResourceUtils.getFraction(a,
R.styleable.SuggestionStripView_alphaTypedWord, 1.0f);
- final float alphaAutoCorrect = getFraction(a,
+ final float alphaAutoCorrect = ResourceUtils.getFraction(a,
R.styleable.SuggestionStripView_alphaAutoCorrect, 1.0f);
- final float alphaSuggested = getFraction(a,
+ final float alphaSuggested = ResourceUtils.getFraction(a,
R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
- mAlphaObsoleted = getFraction(a,
+ mAlphaObsoleted = ResourceUtils.getFraction(a,
R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
mColorValidTypedWord = applyAlpha(a.getColor(
R.styleable.SuggestionStripView_colorValidTypedWord, 0), alphaValidTypedWord);
@@ -217,13 +218,13 @@ public class SuggestionStripView extends RelativeLayout implements OnClickListen
mSuggestionsCountInStrip = a.getInt(
R.styleable.SuggestionStripView_suggestionsCountInStrip,
DEFAULT_SUGGESTIONS_COUNT_IN_STRIP);
- mCenterSuggestionWeight = getFraction(a,
+ mCenterSuggestionWeight = ResourceUtils.getFraction(a,
R.styleable.SuggestionStripView_centerSuggestionPercentile,
DEFAULT_CENTER_SUGGESTION_PERCENTILE);
mMaxMoreSuggestionsRow = a.getInt(
R.styleable.SuggestionStripView_maxMoreSuggestionsRow,
DEFAULT_MAX_MORE_SUGGESTIONS_ROW);
- mMinMoreSuggestionsWidth = getFraction(a,
+ mMinMoreSuggestionsWidth = ResourceUtils.getFraction(a,
R.styleable.SuggestionStripView_minMoreSuggestionsWidth, 1.0f);
a.recycle();
@@ -278,10 +279,6 @@ public class SuggestionStripView extends RelativeLayout implements OnClickListen
return new BitmapDrawable(res, buffer);
}
- static float getFraction(final TypedArray a, final int index, final float defValue) {
- return a.getFraction(index, 1, 1, defValue);
- }
-
private CharSequence getStyledSuggestionWord(SuggestedWords suggestedWords, int pos) {
final CharSequence word = suggestedWords.getWord(pos);
final boolean isAutoCorrect = pos == 1 && suggestedWords.willAutoCorrect();
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index 71a6d6a78..cd9ff85f8 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -257,7 +257,7 @@ public class ResearchLog {
for (Key keyboardKey : keyboardKeys) {
mJsonWriter.beginObject();
mJsonWriter.name("code").value(keyboardKey.mCode);
- mJsonWriter.name("altCode").value(keyboardKey.mAltCode);
+ mJsonWriter.name("altCode").value(keyboardKey.getAltCode());
mJsonWriter.name("x").value(keyboardKey.mX);
mJsonWriter.name("y").value(keyboardKey.mY);
mJsonWriter.name("w").value(keyboardKey.mWidth);
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 918fcf5a1..9bb81a034 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -1045,7 +1045,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final int y, final boolean ignoreModifierKey, final boolean altersCode,
final int code) {
if (key != null) {
- CharSequence outputText = key.mOutputText;
+ String outputText = key.getOutputText();
final Object[] values = {
Keyboard.printableCode(scrubDigitFromCodePoint(code)), outputText == null ? null
: scrubDigitsFromString(outputText.toString()),