Separate inner classes of keyboard package out under internal package
Change-Id: Ia3969bd5ddec5aa5d81d05ad4cf676d818587922
This commit is contained in:
parent
ded498d4a4
commit
35ff94547c
18 changed files with 1875 additions and 1678 deletions
|
@ -32,9 +32,11 @@ 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;
|
||||
|
@ -166,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);
|
||||
}
|
||||
|
@ -175,8 +177,9 @@ 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;
|
||||
mWidth = width - params.mHorizontalGap;
|
||||
mHintLabel = hintLabel;
|
||||
|
@ -213,8 +216,8 @@ 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;
|
||||
mHeight = keyHeight - params.mVerticalGap;
|
||||
|
@ -364,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:
|
||||
|
@ -377,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,
|
||||
|
@ -404,7 +407,7 @@ public class Key {
|
|||
});
|
||||
}
|
||||
|
||||
private boolean equals(Key o) {
|
||||
private boolean equals(final Key o) {
|
||||
if (this == o) return true;
|
||||
return o.mX == mX
|
||||
&& o.mY == mY
|
||||
|
@ -427,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);
|
||||
}
|
||||
|
||||
|
@ -444,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";
|
||||
|
@ -455,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;
|
||||
}
|
||||
|
||||
|
@ -501,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;
|
||||
|
@ -512,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;
|
||||
|
@ -606,7 +609,7 @@ public class Key {
|
|||
return (attrs != null) ? attrs.mAltCode : CODE_UNSPECIFIED;
|
||||
}
|
||||
|
||||
public Drawable getIcon(KeyboardIconsSet iconSet, int alpha) {
|
||||
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;
|
||||
|
@ -617,7 +620,7 @@ public class Key {
|
|||
return icon;
|
||||
}
|
||||
|
||||
public Drawable getPreviewIcon(KeyboardIconsSet iconSet) {
|
||||
public Drawable getPreviewIcon(final KeyboardIconsSet iconSet) {
|
||||
final OptionalAttributes attrs = mOptionalAttributes;
|
||||
final int previewIconId = (attrs != null) ? attrs.mPreviewIconId : ICON_UNDEFINED;
|
||||
return previewIconId != ICON_UNDEFINED
|
||||
|
@ -657,7 +660,7 @@ public class Key {
|
|||
return mEnabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
public void setEnabled(final boolean enabled) {
|
||||
mEnabled = enabled;
|
||||
}
|
||||
|
||||
|
@ -667,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);
|
||||
}
|
||||
|
||||
|
@ -679,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;
|
||||
|
@ -761,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);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,220 +39,222 @@ public class MoreKeysKeyboard extends Keyboard {
|
|||
return mDefaultKeyCoordX;
|
||||
}
|
||||
|
||||
public static class Builder extends Keyboard.Builder<Builder.MoreKeysKeyboardParams> {
|
||||
/* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
private int getFixedOrderTopRowAdjustment() {
|
||||
if (mNumRows == 1 || mTopKeys % 2 == 1 || mTopKeys == mNumColumns
|
||||
|| mLeftKeys == 0 || mRightKeys == 1) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int getAutoOrderTopRowAdjustment() {
|
||||
if (mNumRows == 1 || mTopKeys == 1 || mNumColumns % 2 == mTopKeys % 2
|
||||
|| mLeftKeys == 0 || mRightKeys == 1) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return key position according to column count (0 is default).
|
||||
/* package */int getColumnPos(final int n) {
|
||||
return mIsFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static int getTopRowEmptySlots(final int numKeys, final int numColumns) {
|
||||
final int remainings = numKeys % numColumns;
|
||||
return remainings == 0 ? 0 : numColumns - remainings;
|
||||
}
|
||||
|
||||
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 getDefaultKeyCoordX() {
|
||||
return mLeftKeys * mColumnWidth;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
private int getFixedOrderTopRowAdjustment() {
|
||||
if (mNumRows == 1 || mTopKeys % 2 == 1 || mTopKeys == mNumColumns
|
||||
|| mLeftKeys == 0 || mRightKeys == 1) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int getAutoOrderTopRowAdjustment() {
|
||||
if (mNumRows == 1 || mTopKeys == 1 || mNumColumns % 2 == mTopKeys % 2
|
||||
|| mLeftKeys == 0 || mRightKeys == 1) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return key position according to column count (0 is default).
|
||||
/* package */int getColumnPos(int n) {
|
||||
return mIsFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static int getTopRowEmptySlots(int numKeys, int numColumns) {
|
||||
final int remainings = numKeys % numColumns;
|
||||
return remainings == 0 ? 0 : numColumns - remainings;
|
||||
}
|
||||
|
||||
private int getOptimizedColumns(int numKeys, int maxColumns) {
|
||||
int numColumns = Math.min(numKeys, maxColumns);
|
||||
while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
|
||||
numColumns--;
|
||||
}
|
||||
return numColumns;
|
||||
}
|
||||
|
||||
public int getDefaultKeyCoordX() {
|
||||
return mLeftKeys * mColumnWidth;
|
||||
}
|
||||
|
||||
public int getX(int n, int row) {
|
||||
final int x = getColumnPos(n) * mColumnWidth + getDefaultKeyCoordX();
|
||||
if (isTopRow(row)) {
|
||||
return x + mTopRowAdjustment * (mColumnWidth / 2);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY(int row) {
|
||||
return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding;
|
||||
}
|
||||
|
||||
public void markAsEdgeKey(Key key, int row) {
|
||||
if (row == 0)
|
||||
key.markAsTopEdge(this);
|
||||
if (isTopRow(row))
|
||||
key.markAsBottomEdge(this);
|
||||
}
|
||||
|
||||
private boolean isTopRow(int rowCount) {
|
||||
return mNumRows > 1 && rowCount == mNumRows - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The builder of MoreKeysKeyboard.
|
||||
|
@ -258,7 +262,8 @@ public class MoreKeysKeyboard extends Keyboard {
|
|||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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("",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
private static class EmptyKeyStyle extends KeyStyle {
|
||||
EmptyKeyStyle(final KeyboardTextsSet textsSet) {
|
||||
super(textsSet);
|
||||
}
|
||||
|
||||
protected String[] parseStringArray(TypedArray a, int index) {
|
||||
if (a.hasValue(index)) {
|
||||
return KeySpecParser.parseCsvString(a.getString(index), mTextsSet);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
|
@ -0,0 +1,829 @@
|
|||
/*
|
||||
* 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>
|
||||
* <!-- xml/keyboard.xml -->
|
||||
* <Keyboard keyboard_attributes*>
|
||||
* <!-- Keyboard Content -->
|
||||
* <Row row_attributes*>
|
||||
* <!-- Row Content -->
|
||||
* <Key key_attributes* />
|
||||
* <Spacer horizontalGap="32.0dp" />
|
||||
* <include keyboardLayout="@xml/other_keys">
|
||||
* ...
|
||||
* </Row>
|
||||
* <include keyboardLayout="@xml/other_rows">
|
||||
* ...
|
||||
* </Keyboard>
|
||||
* </pre>
|
||||
* The XML file which is included in other file must have <merge> as root element,
|
||||
* such as:
|
||||
* <pre>
|
||||
* <!-- xml/other_keys.xml -->
|
||||
* <merge>
|
||||
* <Key key_attributes* />
|
||||
* ...
|
||||
* </merge>
|
||||
* </pre>
|
||||
* and
|
||||
* <pre>
|
||||
* <!-- xml/other_rows.xml -->
|
||||
* <merge>
|
||||
* <Row row_attributes*>
|
||||
* <Key key_attributes* />
|
||||
* </Row>
|
||||
* ...
|
||||
* </merge>
|
||||
* </pre>
|
||||
* You can also use switch-case-default tags to select Rows and Keys.
|
||||
* <pre>
|
||||
* <switch>
|
||||
* <case case_attribute*>
|
||||
* <!-- Any valid tags at switch position -->
|
||||
* </case>
|
||||
* ...
|
||||
* <default>
|
||||
* <!-- Any valid tags at switch position -->
|
||||
* </default>
|
||||
* </switch>
|
||||
* </pre>
|
||||
* You can declare Key style and specify styles within Key tags.
|
||||
* <pre>
|
||||
* <switch>
|
||||
* <case mode="email">
|
||||
* <key-style styleName="f1-key" parentStyle="modifier-key"
|
||||
* keyLabel=".com"
|
||||
* />
|
||||
* </case>
|
||||
* <case mode="url">
|
||||
* <key-style styleName="f1-key" parentStyle="modifier-key"
|
||||
* keyLabel="http://"
|
||||
* />
|
||||
* </case>
|
||||
* </switch>
|
||||
* ...
|
||||
* <Key keyStyle="shift-key" ... />
|
||||
* </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);
|
||||
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 = 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 (keyboardViewAttr.hasValue(R.styleable.KeyboardView_keyTypeface)) {
|
||||
params.mKeyTypeface = Typeface.defaultFromStyle(keyboardViewAttr.getInt(
|
||||
R.styleable.KeyboardView_keyTypeface, Typeface.NORMAL));
|
||||
}
|
||||
params.mKeyLetterRatio = ResourceUtils.getFraction(keyboardViewAttr,
|
||||
R.styleable.KeyboardView_keyLetterSize);
|
||||
params.mKeyLetterSize = ResourceUtils.getDimensionPixelSize(keyboardViewAttr,
|
||||
R.styleable.KeyboardView_keyLetterSize);
|
||||
params.mKeyHintLetterRatio = ResourceUtils.getFraction(keyboardViewAttr,
|
||||
R.styleable.KeyboardView_keyHintLetterRatio);
|
||||
params.mKeyShiftedLetterHintRatio = ResourceUtils.getFraction(keyboardViewAttr,
|
||||
R.styleable.KeyboardView_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 {
|
||||
keyboardViewAttr.recycle();
|
||||
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)) : "";
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 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 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;
|
||||
}
|
||||
mNumColumnsInRow[row] = pos - rowStartPos;
|
||||
rowStartPos = pos;
|
||||
row++;
|
||||
}
|
||||
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(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(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++;
|
||||
}
|
||||
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(final int pos) {
|
||||
return mNumColumnsInRow[mRowNumbers[pos]];
|
||||
}
|
||||
|
||||
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 getX(final int pos) {
|
||||
final int columnNumber = getColumnNumber(pos);
|
||||
return columnNumber * (getWidth(pos) + mDividerWidth);
|
||||
}
|
||||
|
||||
public int getY(final int pos) {
|
||||
final int row = mRowNumbers[pos];
|
||||
return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
|
||||
}
|
||||
|
||||
public int getWidth(final int pos) {
|
||||
final int numColumnInRow = getNumColumnInRow(pos);
|
||||
return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
|
||||
}
|
||||
|
||||
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 static class Builder extends KeyboardBuilder<MoreSuggestionsParam> {
|
||||
private final MoreSuggestionsView mPaneView;
|
||||
private SuggestedWords mSuggestions;
|
||||
private int mFromPos;
|
||||
private int mToPos;
|
||||
|
||||
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++;
|
||||
}
|
||||
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 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));
|
||||
}
|
||||
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]];
|
||||
}
|
||||
|
||||
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 getX(int pos) {
|
||||
final int columnNumber = getColumnNumber(pos);
|
||||
return columnNumber * (getWidth(pos) + mDividerWidth);
|
||||
}
|
||||
|
||||
public int getY(int pos) {
|
||||
final int row = mRowNumbers[pos];
|
||||
return (mNumRows -1 - row) * mDefaultRowHeight + mTopPadding;
|
||||
}
|
||||
|
||||
public int getWidth(int pos) {
|
||||
final int numColumnInRow = getNumColumnInRow(pos);
|
||||
return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package com.android.inputmethod.keyboard;
|
|||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import com.android.inputmethod.keyboard.MoreKeysKeyboard.Builder.MoreKeysKeyboardParams;
|
||||
import com.android.inputmethod.keyboard.MoreKeysKeyboard.MoreKeysKeyboardParams;
|
||||
|
||||
public class MoreKeysKeyboardBuilderFixedOrderTests extends AndroidTestCase {
|
||||
private static final int WIDTH = 10;
|
||||
|
|
|
@ -18,7 +18,7 @@ package com.android.inputmethod.keyboard;
|
|||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import com.android.inputmethod.keyboard.MoreKeysKeyboard.Builder.MoreKeysKeyboardParams;
|
||||
import com.android.inputmethod.keyboard.MoreKeysKeyboard.MoreKeysKeyboardParams;
|
||||
|
||||
public class MoreKeysKeyboardBuilderTests extends AndroidTestCase {
|
||||
private static final int WIDTH = 10;
|
||||
|
|
|
@ -23,7 +23,6 @@ import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UN
|
|||
import android.test.AndroidTestCase;
|
||||
|
||||
import com.android.inputmethod.keyboard.Keyboard;
|
||||
import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
|
Loading…
Reference in a new issue