diff options
Diffstat (limited to 'java/src')
19 files changed, 526 insertions, 592 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 68868f12e..8bc7e43b4 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -27,13 +27,13 @@ import android.util.Xml; import com.android.inputmethod.keyboard.internal.KeyStyles; import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.KeyboardParser; import com.android.inputmethod.keyboard.internal.KeyboardParser.ParseException; import com.android.inputmethod.keyboard.internal.PopupCharactersParser; import com.android.inputmethod.keyboard.internal.Row; import com.android.inputmethod.latin.R; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -74,7 +74,9 @@ public class Key { /** Height of the key, not including the gap */ public final int mHeight; /** The horizontal gap around this key */ - public final int mGap; + public final int mHorizontalGap; + /** The vertical gap below this key */ + public final int mVerticalGap; /** The visual insets */ public final int mVisualInsetsLeft; public final int mVisualInsetsRight; @@ -103,9 +105,6 @@ public class Key { /** Whether this key repeats itself when held down */ public final boolean mRepeatable; - /** The Keyboard that this key belongs to */ - private final Keyboard mKeyboard; - /** The current pressed state of this key */ private boolean mPressed; /** If this is a sticky key, is its highlight on? */ @@ -192,13 +191,13 @@ public class Key { /** * This constructor is being used only for key in popup mini keyboard. */ - public Key(Resources res, Keyboard keyboard, CharSequence popupCharacter, int x, int y, + public Key(Resources res, KeyboardParams params, CharSequence popupCharacter, int x, int y, int width, int height, int edgeFlags) { - mKeyboard = keyboard; - mHeight = height - keyboard.getVerticalGap(); - mGap = keyboard.getHorizontalGap(); + mHeight = height - params.mVerticalGap; + mHorizontalGap = params.mHorizontalGap; + mVerticalGap = params.mVerticalGap; mVisualInsetsLeft = mVisualInsetsRight = 0; - mWidth = width - mGap; + mWidth = width - mHorizontalGap; mEdgeFlags = edgeFlags; mHintLabel = null; mLabelOption = 0; @@ -211,10 +210,10 @@ public class Key { mLabel = PopupCharactersParser.getLabel(popupSpecification); mOutputText = PopupCharactersParser.getOutputText(popupSpecification); final int code = PopupCharactersParser.getCode(res, popupSpecification); - mCode = keyboard.isRtlKeyboard() ? getRtlParenthesisCode(code) : code; - mIcon = keyboard.mIconsSet.getIcon(PopupCharactersParser.getIconId(popupSpecification)); + mCode = params.mIsRtlKeyboard ? getRtlParenthesisCode(code) : code; + mIcon = params.mIconsSet.getIcon(PopupCharactersParser.getIconId(popupSpecification)); // Horizontal gap is divided equally to both sides of the key. - mX = x + mGap / 2; + mX = x + mHorizontalGap / 2; mY = y; } @@ -222,16 +221,15 @@ public class Key { * Create a key with the given top-left coordinate and extract its attributes from the XML * parser. * @param res resources associated with the caller's context - * @param row the row that this key belongs to. The row must already be attached to - * a {@link Keyboard}. + * @param params the keyboard building parameters. + * @param row the row that this key belongs to. * @param x the x coordinate of the top-left * @param y the y coordinate of the top-left * @param parser the XML parser containing the attributes for this key * @param keyStyles active key styles set */ - public Key(Resources res, Row row, int x, int y, XmlResourceParser parser, - KeyStyles keyStyles) { - mKeyboard = row.getKeyboard(); + public Key(Resources res, KeyboardParams params, Row row, int x, int y, + XmlResourceParser parser, KeyStyles keyStyles) { final TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard); @@ -239,13 +237,14 @@ public class Key { try { mHeight = KeyboardParser.getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_rowHeight, - mKeyboard.getKeyboardHeight(), row.mDefaultHeight) - row.mVerticalGap; - mGap = KeyboardParser.getDimensionOrFraction(keyboardAttr, + params.mHeight, row.mRowHeight) - params.mVerticalGap; + mHorizontalGap = KeyboardParser.getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_horizontalGap, - mKeyboard.getDisplayWidth(), row.mDefaultHorizontalGap); + params.mWidth, params.mHorizontalGap); + mVerticalGap = params.mVerticalGap; keyWidth = KeyboardParser.getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_keyWidth, - mKeyboard.getDisplayWidth(), row.mDefaultWidth); + params.mWidth, row.mDefaultKeyWidth); } finally { keyboardAttr.recycle(); } @@ -263,7 +262,7 @@ public class Key { style = keyStyles.getEmptyKeyStyle(); } - final int keyboardWidth = mKeyboard.getDisplayWidth(); + final int keyboardWidth = params.mOccupiedWidth; int keyXPos = KeyboardParser.getDimensionOrFraction(keyAttr, R.styleable.Keyboard_Key_keyXPos, keyboardWidth, x); if (keyXPos < 0) { @@ -288,23 +287,28 @@ public class Key { } // Horizontal gap is divided equally to both sides of the key. - mX = keyXPos + mGap / 2; + mX = keyXPos + mHorizontalGap / 2; mY = y; - mWidth = keyWidth - mGap; + mWidth = keyWidth - mHorizontalGap; - final CharSequence[] popupCharacters = style.getTextArray(keyAttr, - R.styleable.Keyboard_Key_popupCharacters); + CharSequence[] popupCharacters = style.getTextArray( + keyAttr, R.styleable.Keyboard_Key_popupCharacters); + if (params.mId.mPasswordInput) { + popupCharacters = PopupCharactersParser.filterOut( + res, popupCharacters, PopupCharactersParser.NON_ASCII_FILTER); + } // In Arabic symbol layouts, we'd like to keep digits in popup characters regardless of // config_digit_popup_characters_enabled. - if (mKeyboard.mId.isAlphabetKeyboard() && !res.getBoolean( + if (params.mId.isAlphabetKeyboard() && !res.getBoolean( R.bool.config_digit_popup_characters_enabled)) { - mPopupCharacters = filterOutDigitPopupCharacters(popupCharacters); + mPopupCharacters = PopupCharactersParser.filterOut( + res, popupCharacters, PopupCharactersParser.DIGIT_FILTER); } else { mPopupCharacters = popupCharacters; } mMaxPopupColumn = style.getInt(keyboardAttr, R.styleable.Keyboard_Key_maxPopupKeyboardColumn, - mKeyboard.getMaxPopupKeyboardColumn()); + params.mMaxPopupColumn); mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false); mFunctional = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isFunctional, false); @@ -312,7 +316,7 @@ public class Key { mEnabled = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_enabled, true); mEdgeFlags = 0; - final KeyboardIconsSet iconsSet = mKeyboard.mIconsSet; + final KeyboardIconsSet iconsSet = params.mIconsSet; mVisualInsetsLeft = KeyboardParser.getDimensionOrFraction(keyAttr, R.styleable.Keyboard_Key_visualInsetsLeft, keyboardWidth, 0); mVisualInsetsRight = KeyboardParser.getDimensionOrFraction(keyAttr, @@ -320,17 +324,14 @@ public class Key { mPreviewIcon = iconsSet.getIcon(style.getInt( keyAttr, R.styleable.Keyboard_Key_keyIconPreview, KeyboardIconsSet.ICON_UNDEFINED)); - Keyboard.setDefaultBounds(mPreviewIcon); mIcon = iconsSet.getIcon(style.getInt( keyAttr, R.styleable.Keyboard_Key_keyIcon, KeyboardIconsSet.ICON_UNDEFINED)); - Keyboard.setDefaultBounds(mIcon); final int shiftedIconId = style.getInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted, KeyboardIconsSet.ICON_UNDEFINED); if (shiftedIconId != KeyboardIconsSet.ICON_UNDEFINED) { final Drawable shiftedIcon = iconsSet.getIcon(shiftedIconId); - Keyboard.setDefaultBounds(shiftedIcon); - mKeyboard.addShiftedIcon(this, shiftedIcon); + params.addShiftedIcon(this, shiftedIcon); } mHintLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel); @@ -343,15 +344,12 @@ public class Key { Keyboard.CODE_UNSPECIFIED); if (code == Keyboard.CODE_UNSPECIFIED && !TextUtils.isEmpty(mLabel)) { final int firstChar = mLabel.charAt(0); - mCode = mKeyboard.isRtlKeyboard() ? getRtlParenthesisCode(firstChar) : firstChar; + mCode = params.mIsRtlKeyboard ? getRtlParenthesisCode(firstChar) : firstChar; } else if (code != Keyboard.CODE_UNSPECIFIED) { mCode = code; } else { mCode = Keyboard.CODE_DUMMY; } - if (mCode == Keyboard.CODE_SHIFT) { - mKeyboard.addShiftKey(this); - } } finally { keyAttr.recycle(); } @@ -361,10 +359,6 @@ public class Key { mEdgeFlags |= flags; } - public CharSequence getCaseAdjustedLabel() { - return mKeyboard.adjustLabelCase(mLabel); - } - public Typeface selectTypeface(Typeface defaultTypeface) { // TODO: Handle "bold" here too? if ((mLabelOption & LABEL_OPTION_FONT_NORMAL) != 0) { @@ -402,36 +396,6 @@ public class Key { return (mLabelOption & LABEL_OPTION_HAS_HINT_LABEL) != 0; } - private static boolean isDigitPopupCharacter(CharSequence label) { - return label != null && label.length() == 1 && Character.isDigit(label.charAt(0)); - } - - private static CharSequence[] filterOutDigitPopupCharacters(CharSequence[] popupCharacters) { - if (popupCharacters == null || popupCharacters.length < 1) - return null; - if (popupCharacters.length == 1 && isDigitPopupCharacter( - PopupCharactersParser.getLabel(popupCharacters[0].toString()))) - return null; - ArrayList<CharSequence> filtered = null; - for (int i = 0; i < popupCharacters.length; i++) { - final CharSequence popupSpec = popupCharacters[i]; - if (isDigitPopupCharacter(PopupCharactersParser.getLabel(popupSpec.toString()))) { - if (filtered == null) { - filtered = new ArrayList<CharSequence>(); - for (int j = 0; j < i; j++) - filtered.add(popupCharacters[j]); - } - } else if (filtered != null) { - filtered.add(popupSpec); - } - } - if (filtered == null) - return popupCharacters; - if (filtered.size() == 0) - return null; - return filtered.toArray(new CharSequence[filtered.size()]); - } - public Drawable getIcon() { return mIcon; } @@ -486,10 +450,10 @@ public class Key { * assume that all points between the key and the edge are considered to be on the key. */ public boolean isOnKey(int x, int y) { - final int left = mX - mGap / 2; - final int right = left + mWidth + mGap; + final int left = mX - mHorizontalGap / 2; + final int right = left + mWidth + mHorizontalGap; final int top = mY; - final int bottom = top + mHeight + mKeyboard.getVerticalGap(); + final int bottom = top + mHeight + mVerticalGap; final int flags = mEdgeFlags; if (flags == 0) { return x >= left && x <= right && y >= top && y <= bottom; diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 6d25025c5..53d46a344 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -57,7 +57,7 @@ public class KeyDetector { mCorrectionX = (int)correctionX; mCorrectionY = (int)correctionY; mKeyboard = keyboard; - final int threshold = keyboard.getMostCommonKeyWidth(); + final int threshold = keyboard.mMostCommonKeyWidth; mProximityThresholdSquare = threshold * threshold; } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 8840c79da..809c949df 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -16,24 +16,17 @@ package com.android.inputmethod.keyboard; -import android.content.Context; -import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.text.TextUtils; -import android.util.Log; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; -import com.android.inputmethod.keyboard.internal.KeyboardParser; +import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.KeyboardShiftState; -import com.android.inputmethod.latin.R; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; /** * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard @@ -54,8 +47,6 @@ import java.util.List; * </pre> */ public class Keyboard { - private static final String TAG = Keyboard.class.getSimpleName(); - public static final int EDGE_LEFT = 0x01; public static final int EDGE_RIGHT = 0x02; public static final int EDGE_TOP = 0x04; @@ -93,212 +84,80 @@ public class Keyboard { // Code value representing the code is not specified. public static final int CODE_UNSPECIFIED = -99; - /** Horizontal gap default for all rows */ - private int mDefaultHorizontalGap; + public final KeyboardId mId; + + /** Total height of the keyboard, including the padding and keys */ + public final int mOccupiedHeight; + /** Total width of the keyboard, including the padding and keys */ + public final int mOccupiedWidth; - /** Default key width */ - private int mDefaultWidth; + public final int mHeight; + public final int mWidth; - /** Default key height */ - private int mDefaultHeight; + /** Default row height */ + public final int mDefaultRowHeight; /** Default gap between rows */ - private int mDefaultVerticalGap; + public final int mVerticalGap; + + public final int mMostCommonKeyWidth; /** Popup keyboard template */ - private int mPopupKeyboardResId; + public final int mPopupKeyboardResId; /** Maximum column for popup keyboard */ - private int mMaxPopupColumn; + public final int mMaxPopupColumn; /** True if Right-To-Left keyboard */ - private boolean mIsRtlKeyboard; - - /** List of shift keys in this keyboard and its icons and state */ - private final List<Key> mShiftKeys = new ArrayList<Key>(); - private final HashMap<Key, Drawable> mShiftedIcons = new HashMap<Key, Drawable>(); - private final HashMap<Key, Drawable> mUnshiftedIcons = new HashMap<Key, Drawable>(); - private final HashSet<Key> mShiftLockKeys = new HashSet<Key>(); - private final KeyboardShiftState mShiftState = new KeyboardShiftState(); - - /** Total height of the keyboard, including the padding and keys */ - private int mTotalHeight; - - /** - * Total width (minimum width) of the keyboard, including left side gaps and keys, but not any - * gaps on the right side. - */ - private int mMinWidth; - - /** List of keys in this keyboard */ - private final List<Key> mKeys = new ArrayList<Key>(); - - /** Width of the screen available to fit the keyboard */ - private final int mDisplayWidth; - - /** Height of the screen */ - private final int mDisplayHeight; - - /** Height of keyboard */ - private int mKeyboardHeight; + public final boolean mIsRtlKeyboard; - private int mMostCommonKeyWidth = 0; + /** List of keys and icons in this keyboard */ + public final List<Key> mKeys; + public final List<Key> mShiftKeys; + public final Set<Key> mShiftLockKeys; + public final Map<Key, Drawable> mShiftedIcons; + public final Map<Key, Drawable> mUnshiftedIcons; + public final KeyboardIconsSet mIconsSet; - public final KeyboardId mId; - - public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); - - // Variables for pre-computing nearest keys. - - // TODO: Change GRID_WIDTH and GRID_HEIGHT to private. - public final int GRID_WIDTH; - public final int GRID_HEIGHT; + private final KeyboardShiftState mShiftState = new KeyboardShiftState(); private final ProximityInfo mProximityInfo; - /** - * Creates a keyboard from the given xml key layout file. - * @param context the application or service context - * @param xmlLayoutResId the resource file that contains the keyboard layout and keys. - * @param id keyboard identifier - * @param width keyboard width - */ + public Keyboard(KeyboardParams params) { + mId = params.mId; + mOccupiedHeight = params.mOccupiedHeight; + mOccupiedWidth = params.mOccupiedWidth; + mHeight = params.mHeight; + mWidth = params.mWidth; + mMostCommonKeyWidth = params.mMostCommonKeyWidth; + mIsRtlKeyboard = params.mIsRtlKeyboard; + mPopupKeyboardResId = params.mPopupKeyboardResId; + mMaxPopupColumn = params.mMaxPopupColumn; + + mDefaultRowHeight = params.mDefaultRowHeight; + mVerticalGap = params.mVerticalGap; + + mKeys = Collections.unmodifiableList(params.mKeys); + mShiftKeys = Collections.unmodifiableList(params.mShiftKeys); + mShiftLockKeys = Collections.unmodifiableSet(params.mShiftLockKeys); + mShiftedIcons = Collections.unmodifiableMap(params.mShiftedIcons); + mUnshiftedIcons = Collections.unmodifiableMap(params.mUnshiftedIcons); + mIconsSet = params.mIconsSet; - public Keyboard(Context context, int xmlLayoutResId, KeyboardId id, int width) { - final Resources res = context.getResources(); - GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); - GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); - - final int horizontalEdgesPadding = (int)res.getDimension( - R.dimen.keyboard_horizontal_edges_padding); - mDisplayWidth = width - horizontalEdgesPadding * 2; - // TODO: Adjust the height by referring to the height of area available for drawing as well. - mDisplayHeight = res.getDisplayMetrics().heightPixels; - - mDefaultHorizontalGap = 0; - setKeyWidth(mDisplayWidth / 10); - mDefaultVerticalGap = 0; - mDefaultHeight = mDefaultWidth; - mId = id; - loadKeyboard(context, xmlLayoutResId); mProximityInfo = new ProximityInfo( - GRID_WIDTH, GRID_HEIGHT, getMinWidth(), getHeight(), getKeyWidth(), mKeys); + params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, + mMostCommonKeyWidth, mKeys); } public int getProximityInfo() { return mProximityInfo.getNativeProximityInfo(); } + // TODO: Access mKeys directly public List<Key> getKeys() { return mKeys; } - public int getHorizontalGap() { - return mDefaultHorizontalGap; - } - - public void setHorizontalGap(int gap) { - mDefaultHorizontalGap = gap; - } - - public int getVerticalGap() { - return mDefaultVerticalGap; - } - - public void setVerticalGap(int gap) { - mDefaultVerticalGap = gap; - } - - public int getRowHeight() { - return mDefaultHeight; - } - - public void setRowHeight(int height) { - mDefaultHeight = height; - } - - public int getKeyWidth() { - return mDefaultWidth; - } - - public void setKeyWidth(int width) { - mDefaultWidth = width; - } - - /** - * Returns the total height of the keyboard - * @return the total height of the keyboard - */ - public int getHeight() { - return mTotalHeight; - } - - public void setHeight(int height) { - mTotalHeight = height; - } - - public int getMinWidth() { - return mMinWidth; - } - - public void setMinWidth(int minWidth) { - mMinWidth = minWidth; - } - - public int getDisplayHeight() { - return mDisplayHeight; - } - - public int getDisplayWidth() { - return mDisplayWidth; - } - - public int getKeyboardHeight() { - return mKeyboardHeight; - } - - public void setKeyboardHeight(int height) { - mKeyboardHeight = height; - } - - public boolean isRtlKeyboard() { - return mIsRtlKeyboard; - } - - public void setRtlKeyboard(boolean isRtl) { - mIsRtlKeyboard = isRtl; - } - - public int getPopupKeyboardResId() { - return mPopupKeyboardResId; - } - - public void setPopupKeyboardResId(int resId) { - mPopupKeyboardResId = resId; - } - - public int getMaxPopupKeyboardColumn() { - return mMaxPopupColumn; - } - - public void setMaxPopupKeyboardColumn(int column) { - mMaxPopupColumn = column; - } - - public void addShiftKey(Key key) { - if (key == null) return; - mShiftKeys.add(key); - if (key.mSticky) { - mShiftLockKeys.add(key); - } - } - - public void addShiftedIcon(Key key, Drawable icon) { - if (key == null) return; - mUnshiftedIcons.put(key, key.getIcon()); - mShiftedIcons.put(key, icon); - } - public boolean hasShiftLockKey() { return !mShiftLockKeys.isEmpty(); } @@ -389,52 +248,4 @@ public class Keyboard { public int[] getNearestKeys(int x, int y) { return mProximityInfo.getNearestKeys(x, y); } - - /** - * Compute the most common key width in order to use it as proximity key detection threshold. - * - * @return The most common key width in the keyboard - */ - public int getMostCommonKeyWidth() { - if (mMostCommonKeyWidth == 0) { - final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>(); - int maxCount = 0; - int mostCommonWidth = 0; - for (final Key key : mKeys) { - final Integer width = key.mWidth + key.mGap; - Integer count = histogram.get(width); - if (count == null) - count = 0; - histogram.put(width, ++count); - if (count > maxCount) { - maxCount = count; - mostCommonWidth = width; - } - } - mMostCommonKeyWidth = mostCommonWidth; - } - return mMostCommonKeyWidth; - } - - private void loadKeyboard(Context context, int xmlLayoutResId) { - try { - KeyboardParser parser = new KeyboardParser(this, context); - parser.parseKeyboard(xmlLayoutResId); - // mMinWidth is the width of this keyboard which is maximum width of row. - mMinWidth = parser.getMaxRowWidth(); - mTotalHeight = parser.getTotalHeight(); - } catch (XmlPullParserException e) { - Log.w(TAG, "keyboard XML parse error: " + e); - throw new IllegalArgumentException(e); - } catch (IOException e) { - Log.w(TAG, "keyboard XML parse error: " + e); - throw new RuntimeException(e); - } - } - - public static void setDefaultBounds(Drawable drawable) { - if (drawable != null) - drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight()); - } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index 9299c6c58..d0a2f864c 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -42,8 +42,6 @@ public class KeyboardId { public static final int F2KEY_MODE_SHORTCUT_IME = 2; public static final int F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS = 3; - private static final int MINI_KEYBOARD_ID_MARKER = -1; - public final Locale mLocale; public final int mOrientation; public final int mWidth; @@ -110,9 +108,9 @@ public class KeyboardId { }); } - public KeyboardId cloneAsMiniKeyboard() { - return new KeyboardId("mini popup keyboard", MINI_KEYBOARD_ID_MARKER, mLocale, mOrientation, - mWidth, mMode, mAttribute, false, F2KEY_MODE_NONE, false, false, false); + public KeyboardId cloneWithNewXml(String xmlName, int xmlId) { + return new KeyboardId(xmlName, xmlId, mLocale, mOrientation, mWidth, mMode, mAttribute, + false, F2KEY_MODE_NONE, false, false, false); } public KeyboardId cloneWithNewGeometry(int orientation, int width) { @@ -127,10 +125,6 @@ public class KeyboardId { return mXmlId; } - public boolean isMiniKeyboard() { - return mXmlId == MINI_KEYBOARD_ID_MARKER; - } - public boolean isAlphabetKeyboard() { return mXmlId == R.xml.kbd_qwerty; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 17fdd0cc4..f45e81090 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -29,7 +29,6 @@ import android.view.View; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.keyboard.internal.ModifierKeyState; import com.android.inputmethod.keyboard.internal.ShiftKeyState; import com.android.inputmethod.latin.LatinIME; @@ -270,14 +269,17 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha if (keyboard == null) { final Locale savedLocale = Utils.setSystemLocale( mResources, mSubtypeSwitcher.getInputLocale()); - - keyboard = new LatinKeyboard(mThemeContext, id, id.mWidth); + try { + keyboard = new LatinKeyboard.Builder(mThemeContext).load(id).build(); + } finally { + Utils.setSystemLocale(mResources, savedLocale); + } mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard)); - if (DEBUG_CACHE) + + if (DEBUG_CACHE) { Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": " + ((ref == null) ? "LOAD" : "GCed") + " id=" + id); - - Utils.setSystemLocale(mResources, savedLocale); + } } else if (DEBUG_CACHE) { Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 4086a8e77..0fb510948 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -357,7 +357,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mDirtyRect.set(0, 0, getWidth(), getHeight()); mBufferNeedsUpdate = true; invalidateAllKeys(); - final int keyHeight = keyboard.getRowHeight() - keyboard.getVerticalGap(); + final int keyHeight = keyboard.mDefaultRowHeight - keyboard.mVerticalGap; mKeyDrawParams.updateKeyHeight(keyHeight); mKeyPreviewDrawParams.updateKeyHeight(keyHeight); } @@ -396,7 +396,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mKeyboard != null) { // The main keyboard expands to the display width. - final int height = mKeyboard.getKeyboardHeight() + getPaddingTop() + getPaddingBottom(); + final int height = mKeyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); setMeasuredDimension(widthMeasureSpec, height); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -443,7 +443,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { + getPaddingLeft(); final int keyDrawY = mInvalidatedKey.mY + getPaddingTop(); canvas.translate(keyDrawX, keyDrawY); - onBufferDrawKey(mInvalidatedKey, canvas, mPaint, params, isManualTemporaryUpperCase); + onBufferDrawKey(mInvalidatedKey, mKeyboard, canvas, mPaint, params, + isManualTemporaryUpperCase); canvas.translate(-keyDrawX, -keyDrawY); } else { // Draw all keys. @@ -451,7 +452,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final int keyDrawX = key.mX + key.mVisualInsetsLeft + getPaddingLeft(); final int keyDrawY = key.mY + getPaddingTop(); canvas.translate(keyDrawX, keyDrawY); - onBufferDrawKey(key, canvas, mPaint, params, isManualTemporaryUpperCase); + onBufferDrawKey(key, mKeyboard, canvas, mPaint, params, isManualTemporaryUpperCase); canvas.translate(-keyDrawX, -keyDrawY); } } @@ -470,8 +471,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { return false; } - private static void onBufferDrawKey(final Key key, final Canvas canvas, Paint paint, - KeyDrawParams params, boolean isManualTemporaryUpperCase) { + private static void onBufferDrawKey(final Key key, final Keyboard keyboard, final Canvas canvas, + Paint paint, KeyDrawParams params, boolean isManualTemporaryUpperCase) { final boolean debugShowAlign = LatinImeLogger.sVISUALDEBUG; // Draw key background. final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight @@ -507,7 +508,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { float positionX = centerX; if (key.mLabel != null) { // Switch the character to uppercase if shift is pressed - final CharSequence label = key.getCaseAdjustedLabel(); + final CharSequence label = keyboard.adjustLabelCase(key.mLabel); // For characters, use large font. For labels like "Done", use smaller font. paint.setTypeface(key.selectTypeface(params.mKeyTextStyle)); final int labelSize = key.selectTextSize(params.mKeyLetterSize, @@ -798,7 +799,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mPreviewTextSize); previewText.setTypeface(params.mKeyTextStyle); } - previewText.setText(key.getCaseAdjustedLabel()); + previewText.setText(mKeyboard.adjustLabelCase(key.mLabel)); } else { final Drawable previewIcon = key.getPreviewIcon(); previewText.setCompoundDrawables(null, null, null, diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java index 3c27129ec..9a13608fd 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -31,13 +31,14 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.text.TextUtils; +import com.android.inputmethod.keyboard.internal.KeyboardParams; +import com.android.inputmethod.keyboard.internal.KeyboardParser; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; import java.lang.ref.SoftReference; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Locale; // TODO: We should remove this class @@ -73,32 +74,16 @@ public class LatinKeyboard extends Keyboard { private static final String SMALL_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "small"; private static final String MEDIUM_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "medium"; - public LatinKeyboard(Context context, KeyboardId id, int width) { - super(context, id.getXmlId(), id, width); + private LatinKeyboard(Context context, LatinKeyboardParams params) { + super(params); mRes = context.getResources(); mTheme = context.getTheme(); - final List<Key> keys = getKeys(); - int spaceKeyIndex = -1; - int shortcutKeyIndex = -1; - final int keyCount = keys.size(); - for (int index = 0; index < keyCount; index++) { - // For now, assuming there are up to one space key and one shortcut key respectively. - switch (keys.get(index).mCode) { - case CODE_SPACE: - spaceKeyIndex = index; - break; - case CODE_SHORTCUT: - shortcutKeyIndex = index; - break; - } - } - // The index of space key is available only after Keyboard constructor has finished. - mSpaceKey = (spaceKeyIndex >= 0) ? keys.get(spaceKeyIndex) : null; + mSpaceKey = params.mSpaceKey; mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon() : null; - mShortcutKey = (shortcutKeyIndex >= 0) ? keys.get(shortcutKeyIndex) : null; + mShortcutKey = params.mShortcutKey; mEnabledShortcutIcon = (mShortcutKey != null) ? mShortcutKey.getIcon() : null; final TypedArray a = context.obtainStyledAttributes( @@ -114,6 +99,42 @@ public class LatinKeyboard extends Keyboard { a.recycle(); } + private static class LatinKeyboardParams extends KeyboardParams { + public Key mSpaceKey = null; + public Key mShortcutKey = null; + + @Override + public void onAddKey(Key key) { + super.onAddKey(key); + + switch (key.mCode) { + case Keyboard.CODE_SPACE: + mSpaceKey = key; + break; + case Keyboard.CODE_SHORTCUT: + mShortcutKey = key; + break; + } + } + } + + public static class Builder extends KeyboardParser<LatinKeyboardParams> { + public Builder(Context context) { + super(context, new LatinKeyboardParams()); + } + + @Override + public Builder load(KeyboardId id) { + super.load(id); + return this; + } + + @Override + public LatinKeyboard build() { + return new LatinKeyboard(mContext, mParams); + } + } + public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboardView view) { mSpacebarTextFadeFactor = fadeFactor; updateSpacebarForLocale(false); @@ -294,8 +315,8 @@ public class LatinKeyboard extends Keyboard { @Override public int[] getNearestKeys(int x, int y) { // Avoid dead pixels at edges of the keyboard - return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)), - Math.max(0, Math.min(y, getHeight() - 1))); + return super.getNearestKeys(Math.max(0, Math.min(x, mOccupiedWidth - 1)), + Math.max(0, Math.min(y, mOccupiedHeight - 1))); } public static int getTextSizeFromTheme(Theme theme, int style, int defValue) { diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java index b397ca757..abf28c73c 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java @@ -289,7 +289,7 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke super.setKeyboard(keyboard); mKeyDetector.setKeyboard( keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); - mKeyDetector.setProximityThreshold(keyboard.getMostCommonKeyWidth()); + mKeyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); PointerTracker.setKeyDetector(mKeyDetector); mPopupPanelCache.clear(); } @@ -360,7 +360,7 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke (PopupMiniKeyboardView)container.findViewById(R.id.mini_keyboard_view); final Keyboard parentKeyboard = getKeyboard(); final Keyboard miniKeyboard = new MiniKeyboardBuilder( - this, parentKeyboard.getPopupKeyboardResId(), parentKey, parentKeyboard).build(); + this, parentKeyboard.mPopupKeyboardResId, parentKey, parentKeyboard).build(); miniKeyboardView.setKeyboard(miniKeyboard); container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index b78fd94ea..04096778b 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -69,7 +69,7 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { public void setKeyboard(Keyboard newKeyboard) { super.setKeyboard(newKeyboard); // One-seventh of the keyboard width seems like a reasonable threshold - final int jumpThreshold = newKeyboard.getMinWidth() / 7; + final int jumpThreshold = newKeyboard.mOccupiedWidth / 7; mJumpThresholdSquare = jumpThreshold * jumpThreshold; } diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java index 95e32755e..7f5339de5 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java @@ -16,30 +16,14 @@ package com.android.inputmethod.keyboard; -import android.content.Context; +import com.android.inputmethod.keyboard.internal.MiniKeyboardBuilder.MiniKeyboardLayoutParams; public class MiniKeyboard extends Keyboard { - private int mDefaultKeyCoordX; + private final int mDefaultKeyCoordX; - public MiniKeyboard(Context context, int xmlLayoutResId, Keyboard parentKeyboard) { - super(context, xmlLayoutResId, parentKeyboard.mId.cloneAsMiniKeyboard(), - parentKeyboard.getMinWidth()); - // HACK: Current mini keyboard design totally relies on the 9-patch padding about horizontal - // and vertical key spacing. To keep the visual of mini keyboard as is, these hacks are - // needed to keep having the same horizontal and vertical key spacing. - setHorizontalGap(0); - setVerticalGap(parentKeyboard.getVerticalGap() / 2); - - // TODO: When we have correctly padded key background 9-patch drawables for mini keyboard, - // revert the above hacks and uncomment the following lines. - //setHorizontalGap(parentKeyboard.getHorizontalGap()); - //setVerticalGap(parentKeyboard.getVerticalGap()); - - setRtlKeyboard(parentKeyboard.isRtlKeyboard()); - } - - public void setDefaultCoordX(int pos) { - mDefaultKeyCoordX = pos; + public MiniKeyboard(MiniKeyboardLayoutParams params) { + super(params); + mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2; } public int getDefaultCoordX() { diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index b25754de4..3d8a9cfc6 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -286,7 +286,7 @@ public class PointerTracker { mKeyDetector = keyDetector; mKeyboard = keyDetector.getKeyboard(); mKeys = mKeyboard.getKeys(); - final int keyQuarterWidth = mKeyboard.getKeyWidth() / 4; + final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4; mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; } diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java index 2741ee80b..dfaaa707c 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java @@ -108,8 +108,8 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final Keyboard keyboard = getKeyboard(); if (keyboard != null) { - final int width = keyboard.getMinWidth() + getPaddingLeft() + getPaddingRight(); - final int height = keyboard.getKeyboardHeight() + getPaddingTop() + getPaddingBottom(); + final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); + final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); setMeasuredDimension(width, height); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -170,9 +170,9 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { final int miniKeyboardLeft = pointX - miniKeyboard.getDefaultCoordX() + parentKeyboardView.getPaddingLeft(); final int x = Math.max(0, Math.min(miniKeyboardLeft, - parentKeyboardView.getWidth() - miniKeyboard.getMinWidth())) + parentKeyboardView.getWidth() - miniKeyboard.mOccupiedWidth)) - container.getPaddingLeft() + mCoordinates[0]; - final int y = pointY - parentKeyboard.getVerticalGap() + final int y = pointY - parentKeyboard.mVerticalGap - (container.getMeasuredHeight() - container.getPaddingBottom()) + parentKeyboardView.getPaddingTop() + mCoordinates[1]; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index 02c261bcd..ed4608bf6 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -21,7 +21,6 @@ import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.util.Log; -import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.R; public class KeyboardIconsSet { @@ -51,7 +50,7 @@ public class KeyboardIconsSet { private final Drawable mIcons[] = new Drawable[ICON_LAST + 1]; - private static final int getIconId(int attrIndex) { + private static final int getIconId(final int attrIndex) { switch (attrIndex) { case R.styleable.Keyboard_iconShiftKey: return ICON_SHIFT_KEY; @@ -86,16 +85,14 @@ public class KeyboardIconsSet { } } - public void loadIcons(TypedArray keyboardAttrs) { + public void loadIcons(final TypedArray keyboardAttrs) { final int count = keyboardAttrs.getIndexCount(); for (int i = 0; i < count; i++) { final int attrIndex = keyboardAttrs.getIndex(i); final int iconId = getIconId(attrIndex); if (iconId != ICON_UNDEFINED) { try { - final Drawable icon = keyboardAttrs.getDrawable(attrIndex); - Keyboard.setDefaultBounds(icon); - mIcons[iconId] = icon; + mIcons[iconId] = setDefaultBounds(keyboardAttrs.getDrawable(attrIndex)); } catch (Resources.NotFoundException e) { Log.w(TAG, "Drawable resource for icon #" + iconId + " not found"); } @@ -103,11 +100,18 @@ public class KeyboardIconsSet { } } - public Drawable getIcon(int iconId) { + public Drawable getIcon(final int iconId) { if (iconId == ICON_UNDEFINED) return null; if (iconId < 0 || iconId >= mIcons.length) throw new IllegalArgumentException("icon id is out of range: " + iconId); return mIcons[iconId]; } + + private static Drawable setDefaultBounds(final Drawable icon) { + if (icon != null) { + icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); + } + return icon; + } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java new file mode 100644 index 000000000..4ccaa72d2 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 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.drawable.Drawable; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardId; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class KeyboardParams { + public KeyboardId mId; + + public int mOccupiedHeight; + public int mOccupiedWidth; + + public int mHeight; + public int mWidth; + + public int mTopPadding; + public int mBottomPadding; + public int mHorizontalEdgesPadding; + public int mHorizontalCenterPadding; + + public int mDefaultRowHeight; + public int mDefaultKeyWidth; + public int mHorizontalGap; + public int mVerticalGap; + + public boolean mIsRtlKeyboard; + public int mPopupKeyboardResId; + public int mMaxPopupColumn; + + public int GRID_WIDTH; + public int GRID_HEIGHT; + + public final List<Key> mKeys = new ArrayList<Key>(); + public final List<Key> mShiftKeys = new ArrayList<Key>(); + public final Set<Key> mShiftLockKeys = new HashSet<Key>(); + public final Map<Key, Drawable> mShiftedIcons = new HashMap<Key, Drawable>(); + public final Map<Key, Drawable> mUnshiftedIcons = new HashMap<Key, Drawable>(); + public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); + + public int mMostCommonKeyWidth = 0; + + public void onAddKey(Key key) { + mKeys.add(key); + updateHistogram(key); + if (key.mCode == Keyboard.CODE_SHIFT) { + mShiftKeys.add(key); + if (key.mSticky) { + mShiftLockKeys.add(key); + } + } + } + + public void addShiftedIcon(Key key, Drawable icon) { + mUnshiftedIcons.put(key, key.getIcon()); + mShiftedIcons.put(key, icon); + } + + private int mMaxCount = 0; + private final Map<Integer, Integer> mHistogram = new HashMap<Integer, Integer>(); + + private void updateHistogram(Key key) { + final Integer width = key.mWidth + key.mHorizontalGap; + final int count = (mHistogram.containsKey(width) ? mHistogram.get(width) : 0) + 1; + mHistogram.put(width, count); + if (count > mMaxCount) { + mMaxCount = count; + mMostCommonKeyWidth = width; + } + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java index f6f46750c..42e290f8c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.util.Xml; @@ -107,7 +108,7 @@ import java.util.List; * </pre> */ -public class KeyboardParser { +public class KeyboardParser<KP extends KeyboardParams> { private static final String TAG = KeyboardParser.class.getSimpleName(); private static final boolean DEBUG = false; @@ -123,40 +124,52 @@ public class KeyboardParser { private static final String TAG_DEFAULT = "default"; public static final String TAG_KEY_STYLE = "key-style"; - private final Keyboard mKeyboard; - private final Context mContext; - private final Resources mResources; + protected final KP mParams; + protected final Context mContext; + protected final Resources mResources; + private final DisplayMetrics mDisplayMetrics; - private int mKeyboardTopPadding; - private int mKeyboardBottomPadding; - private int mHorizontalEdgesPadding; private int mCurrentX = 0; private int mCurrentY = 0; - private int mMaxRowWidth = 0; - private int mTotalHeight = 0; private Row mCurrentRow = null; private boolean mLeftEdge; private Key mRightEdgeKey = null; private final KeyStyles mKeyStyles = new KeyStyles(); - public KeyboardParser(Keyboard keyboard, Context context) { - mKeyboard = keyboard; + public KeyboardParser(Context context, KP params) { mContext = context; final Resources res = context.getResources(); mResources = res; - mHorizontalEdgesPadding = (int)res.getDimension(R.dimen.keyboard_horizontal_edges_padding); + mDisplayMetrics = res.getDisplayMetrics(); + + mParams = params; + mParams.mHorizontalEdgesPadding = (int)res.getDimension( + R.dimen.keyboard_horizontal_edges_padding); + + mParams.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); + mParams.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); } - public int getMaxRowWidth() { - return mMaxRowWidth; + public KeyboardParser<KP> load(KeyboardId id) { + mParams.mId = id; + try { + parseKeyboard(id.getXmlId()); + } catch (XmlPullParserException e) { + Log.w(TAG, "keyboard XML parse error: " + e); + throw new IllegalArgumentException(e); + } catch (IOException e) { + Log.w(TAG, "keyboard XML parse error: " + e); + throw new RuntimeException(e); + } + return this; } - public int getTotalHeight() { - return mTotalHeight; + public Keyboard build() { + return new Keyboard(mParams); } - public void parseKeyboard(int resId) throws XmlPullParserException, IOException { - if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mKeyboard.mId)); + private void parseKeyboard(int resId) throws XmlPullParserException, IOException { + if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mParams.mId)); final XmlResourceParser parser = mResources.getXml(resId); int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -165,7 +178,7 @@ public class KeyboardParser { if (TAG_KEYBOARD.equals(tag)) { parseKeyboardAttributes(parser); startKeyboard(); - parseKeyboardContent(parser, mKeyboard.getKeys()); + parseKeyboardContent(parser, false); break; } else { throw new IllegalStartTag(parser, TAG_KEYBOARD); @@ -196,15 +209,14 @@ public class KeyboardParser { } private void parseKeyboardAttributes(XmlResourceParser parser) { - final Keyboard keyboard = mKeyboard; - final int displayWidth = keyboard.getDisplayWidth(); + final int displayWidth = mDisplayMetrics.widthPixels; final TypedArray keyboardAttr = mContext.obtainStyledAttributes( Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle, R.style.Keyboard); final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_Key); try { - final int displayHeight = keyboard.getDisplayHeight(); + final int displayHeight = mDisplayMetrics.heightPixels; final int keyboardHeight = (int)keyboardAttr.getDimension( R.styleable.Keyboard_keyboardHeight, displayHeight / 2); final int maxKeyboardHeight = getDimensionOrFraction(keyboardAttr, @@ -219,61 +231,65 @@ public class KeyboardParser { } // Keyboard height will not exceed maxKeyboardHeight and will not be less than // minKeyboardHeight. - final int height = Math.max( + mParams.mOccupiedHeight = Math.max( Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); - - keyboard.setKeyboardHeight(height); - keyboard.setRtlKeyboard(keyboardAttr.getBoolean( - R.styleable.Keyboard_isRtlKeyboard, false)); - keyboard.setKeyWidth(getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_keyWidth, displayWidth, displayWidth / 10)); - keyboard.setRowHeight(getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_rowHeight, height, 50)); - keyboard.setHorizontalGap(getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_horizontalGap, displayWidth, 0)); - keyboard.setVerticalGap(getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_verticalGap, height, 0)); - keyboard.setPopupKeyboardResId(keyboardAttr.getResourceId( - R.styleable.Keyboard_popupKeyboardTemplate, 0)); - keyboard.setMaxPopupKeyboardColumn(keyAttr.getInt( - R.styleable.Keyboard_Key_maxPopupKeyboardColumn, 5)); - - mKeyboard.mIconsSet.loadIcons(keyboardAttr); - mKeyboardTopPadding = getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_keyboardTopPadding, height, 0); - mKeyboardBottomPadding = getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_keyboardBottomPadding, height, 0); + mParams.mOccupiedWidth = mParams.mId.mWidth; + mParams.mTopPadding = getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_keyboardTopPadding, mParams.mOccupiedHeight, 0); + mParams.mBottomPadding = getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_keyboardBottomPadding, mParams.mOccupiedHeight, 0); + + final int height = mParams.mOccupiedHeight; + final int width = mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding * 2 + - mParams.mHorizontalCenterPadding; + mParams.mHeight = height; + mParams.mWidth = width; + mParams.mDefaultKeyWidth = getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_keyWidth, width, width / 10); + mParams.mDefaultRowHeight = getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_rowHeight, height, height / 4); + mParams.mHorizontalGap = getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_horizontalGap, width, 0); + mParams.mVerticalGap = getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_verticalGap, height, 0); + + mParams.mIsRtlKeyboard = keyboardAttr.getBoolean(R.styleable.Keyboard_isRtlKeyboard, false); + mParams.mPopupKeyboardResId = keyboardAttr.getResourceId( + R.styleable.Keyboard_popupKeyboardTemplate, 0); + mParams.mMaxPopupColumn = keyAttr.getInt(R.styleable.Keyboard_Key_maxPopupKeyboardColumn, 5); + + mParams.mIconsSet.loadIcons(keyboardAttr); } finally { keyAttr.recycle(); keyboardAttr.recycle(); } } - private void parseKeyboardContent(XmlResourceParser parser, List<Key> keys) + private void parseKeyboardContent(XmlResourceParser parser, boolean skip) throws XmlPullParserException, IOException { int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_ROW.equals(tag)) { - Row row = new Row(mResources, mKeyboard, parser); + Row row = parseRowAttributes(parser); if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW)); - if (keys != null) + if (!skip) startRow(row); - parseRowContent(parser, row, keys); + parseRowContent(parser, row, skip); } else if (TAG_INCLUDE.equals(tag)) { - parseIncludeKeyboardContent(parser, keys); + parseIncludeKeyboardContent(parser, skip); } else if (TAG_SWITCH.equals(tag)) { - parseSwitchKeyboardContent(parser, keys); + parseSwitchKeyboardContent(parser, skip); } else if (TAG_KEY_STYLE.equals(tag)) { - parseKeyStyle(parser, keys); + parseKeyStyle(parser, skip); } else { throw new IllegalStartTag(parser, TAG_ROW); } } else if (event == XmlPullParser.END_TAG) { final String tag = parser.getName(); if (TAG_KEYBOARD.equals(tag)) { - endKeyboard(mKeyboard.getVerticalGap()); + endKeyboard(); break; } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) || TAG_MERGE.equals(tag)) { @@ -288,22 +304,36 @@ public class KeyboardParser { } } - private void parseRowContent(XmlResourceParser parser, Row row, List<Key> keys) + private Row parseRowAttributes(XmlResourceParser parser) { + final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard); + try { + if (a.hasValue(R.styleable.Keyboard_horizontalGap)) + throw new IllegalAttribute(parser, "horizontalGap"); + if (a.hasValue(R.styleable.Keyboard_verticalGap)) + throw new IllegalAttribute(parser, "verticalGap"); + return new Row(mResources, mParams, parser); + } finally { + a.recycle(); + } + } + + private void parseRowContent(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.START_TAG) { final String tag = parser.getName(); if (TAG_KEY.equals(tag)) { - parseKey(parser, row, keys); + parseKey(parser, row, skip); } else if (TAG_SPACER.equals(tag)) { - parseSpacer(parser, row, keys); + parseSpacer(parser, row, skip); } else if (TAG_INCLUDE.equals(tag)) { - parseIncludeRowContent(parser, row, keys); + parseIncludeRowContent(parser, row, skip); } else if (TAG_SWITCH.equals(tag)) { - parseSwitchRowContent(parser, row, keys); + parseSwitchRowContent(parser, row, skip); } else if (TAG_KEY_STYLE.equals(tag)) { - parseKeyStyle(parser, keys); + parseKeyStyle(parser, skip); } else { throw new IllegalStartTag(parser, TAG_KEY); } @@ -311,7 +341,7 @@ public class KeyboardParser { final String tag = parser.getName(); if (TAG_ROW.equals(tag)) { if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_ROW)); - if (keys != null) + if (!skip) endRow(); break; } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) @@ -327,24 +357,24 @@ public class KeyboardParser { } } - private void parseKey(XmlResourceParser parser, Row row, List<Key> keys) + private void parseKey(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { - if (keys == null) { + if (skip) { checkEndTag(TAG_KEY, parser); } else { - Key key = new Key(mResources, row, mCurrentX, mCurrentY, parser, mKeyStyles); + Key key = new Key(mResources, mParams, row, mCurrentX, mCurrentY, parser, mKeyStyles); if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d popupCharacters=%s />", TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode, Arrays.toString(key.mPopupCharacters))); checkEndTag(TAG_KEY, parser); - keys.add(key); + mParams.onAddKey(key); endKey(key); } } - private void parseSpacer(XmlResourceParser parser, Row row, List<Key> keys) + private void parseSpacer(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { - if (keys == null) { + if (skip) { checkEndTag(TAG_SPACER, parser); } else { if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER)); @@ -352,9 +382,9 @@ public class KeyboardParser { R.styleable.Keyboard); if (keyboardAttr.hasValue(R.styleable.Keyboard_horizontalGap)) throw new IllegalAttribute(parser, "horizontalGap"); - final int keyboardWidth = mKeyboard.getDisplayWidth(); + final int keyboardWidth = mParams.mWidth; final int keyWidth = getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_keyWidth, - keyboardWidth, row.mDefaultWidth); + keyboardWidth, row.mDefaultKeyWidth); keyboardAttr.recycle(); final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), @@ -371,19 +401,19 @@ public class KeyboardParser { } } - private void parseIncludeKeyboardContent(XmlResourceParser parser, List<Key> keys) + private void parseIncludeKeyboardContent(XmlResourceParser parser, boolean skip) throws XmlPullParserException, IOException { - parseIncludeInternal(parser, null, keys); + parseIncludeInternal(parser, null, skip); } - private void parseIncludeRowContent(XmlResourceParser parser, Row row, List<Key> keys) + private void parseIncludeRowContent(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { - parseIncludeInternal(parser, row, keys); + parseIncludeInternal(parser, row, skip); } - private void parseIncludeInternal(XmlResourceParser parser, Row row, List<Key> keys) + private void parseIncludeInternal(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { - if (keys == null) { + if (skip) { checkEndTag(TAG_INCLUDE, parser); } else { final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), @@ -397,11 +427,11 @@ public class KeyboardParser { throw new ParseException("No keyboardLayout attribute in <include/>", parser); if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />", TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout))); - parseMerge(mResources.getLayout(keyboardLayout), row, keys); + parseMerge(mResources.getLayout(keyboardLayout), row, skip); } } - private void parseMerge(XmlResourceParser parser, Row row, List<Key> keys) + private void parseMerge(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -409,9 +439,9 @@ public class KeyboardParser { final String tag = parser.getName(); if (TAG_MERGE.equals(tag)) { if (row == null) { - parseKeyboardContent(parser, keys); + parseKeyboardContent(parser, skip); } else { - parseRowContent(parser, row, keys); + parseRowContent(parser, row, skip); } break; } else { @@ -422,28 +452,28 @@ public class KeyboardParser { } } - private void parseSwitchKeyboardContent(XmlResourceParser parser, List<Key> keys) + private void parseSwitchKeyboardContent(XmlResourceParser parser, boolean skip) throws XmlPullParserException, IOException { - parseSwitchInternal(parser, null, keys); + parseSwitchInternal(parser, null, skip); } - private void parseSwitchRowContent(XmlResourceParser parser, Row row, List<Key> keys) + private void parseSwitchRowContent(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { - parseSwitchInternal(parser, row, keys); + parseSwitchInternal(parser, row, skip); } - private void parseSwitchInternal(XmlResourceParser parser, Row row, List<Key> keys) + private void parseSwitchInternal(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { - if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mKeyboard.mId)); + if (DEBUG) Log.d(TAG, String.format("<%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 ? null : keys); + selected |= parseCase(parser, row, selected ? true : skip); } else if (TAG_DEFAULT.equals(tag)) { - selected |= parseDefault(parser, row, selected ? null : keys); + selected |= parseDefault(parser, row, selected ? true : skip); } else { throw new IllegalStartTag(parser, TAG_KEY); } @@ -459,21 +489,21 @@ public class KeyboardParser { } } - private boolean parseCase(XmlResourceParser parser, Row row, List<Key> keys) + private boolean parseCase(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { final boolean selected = parseCaseCondition(parser); if (row == null) { // Processing Rows. - parseKeyboardContent(parser, selected ? keys : null); + parseKeyboardContent(parser, selected ? skip : true); } else { // Processing Keys. - parseRowContent(parser, row, selected ? keys : null); + parseRowContent(parser, row, selected ? skip : true); } return selected; } private boolean parseCaseCondition(XmlResourceParser parser) { - final KeyboardId id = mKeyboard.mId; + final KeyboardId id = mParams.mId; if (id == null) return true; @@ -582,18 +612,18 @@ public class KeyboardParser { return false; } - private boolean parseDefault(XmlResourceParser parser, Row row, List<Key> keys) + private boolean parseDefault(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT)); if (row == null) { - parseKeyboardContent(parser, keys); + parseKeyboardContent(parser, skip); } else { - parseRowContent(parser, row, keys); + parseRowContent(parser, row, skip); } return true; } - private void parseKeyStyle(XmlResourceParser parser, List<Key> keys) { + private void parseKeyStyle(XmlResourceParser parser, boolean skip) { TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_KeyStyle); TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), @@ -602,7 +632,7 @@ public class KeyboardParser { if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) throw new ParseException("<" + TAG_KEY_STYLE + "/> needs styleName attribute", parser); - if (keys != null) + if (!skip) mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); } finally { keyStyleAttr.recycle(); @@ -618,12 +648,12 @@ public class KeyboardParser { } private void startKeyboard() { - mCurrentY += mKeyboardTopPadding; + mCurrentY += mParams.mTopPadding; } private void startRow(Row row) { mCurrentX = 0; - setSpacer(mCurrentX, mHorizontalEdgesPadding); + setSpacer(mCurrentX, mParams.mHorizontalEdgesPadding); mCurrentRow = row; mLeftEdge = true; mRightEdgeKey = null; @@ -636,15 +666,13 @@ public class KeyboardParser { mRightEdgeKey.addEdgeFlags(Keyboard.EDGE_RIGHT); mRightEdgeKey = null; } - setSpacer(mCurrentX, mHorizontalEdgesPadding); - if (mCurrentX > mMaxRowWidth) - mMaxRowWidth = mCurrentX; - mCurrentY += mCurrentRow.mDefaultHeight; + setSpacer(mCurrentX, mParams.mHorizontalEdgesPadding); + mCurrentY += mCurrentRow.mRowHeight; mCurrentRow = null; } private void endKey(Key key) { - mCurrentX = key.mX - key.mGap / 2 + key.mWidth + key.mGap; + mCurrentX = key.mX - key.mHorizontalGap / 2 + key.mWidth + key.mHorizontalGap; if (mLeftEdge) { key.addEdgeFlags(Keyboard.EDGE_LEFT); mLeftEdge = false; @@ -652,9 +680,7 @@ public class KeyboardParser { mRightEdgeKey = key; } - private void endKeyboard(int defaultVerticalGap) { - mCurrentY += mKeyboardBottomPadding; - mTotalHeight = mCurrentY - defaultVerticalGap; + private void endKeyboard() { } private void setSpacer(int keyXPos, int width) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java index 965c679ea..bad7a1772 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java @@ -16,8 +16,6 @@ package com.android.inputmethod.keyboard.internal; -import android.content.Context; -import android.content.res.Resources; import android.graphics.Paint; import android.graphics.Rect; @@ -27,26 +25,30 @@ import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.MiniKeyboard; import com.android.inputmethod.latin.R; -import java.util.List; - -public class MiniKeyboardBuilder { - private final Resources mRes; - private final MiniKeyboard mKeyboard; +public class MiniKeyboardBuilder extends + KeyboardParser<MiniKeyboardBuilder.MiniKeyboardLayoutParams> { private final CharSequence[] mPopupCharacters; - private final MiniKeyboardLayoutParams mParams; - /* package */ static class MiniKeyboardLayoutParams { - public final int mKeyWidth; - public final int mRowHeight; - /* package */ final int mTopRowAdjustment; - public final int mNumRows; - public final int mNumColumns; - public final int mLeftKeys; - public final int mRightKeys; // includes default key. - public int mTopPadding; + public static class MiniKeyboardLayoutParams extends KeyboardParams { + /* package */ int mTopRowAdjustment; + public int mNumRows; + public int mNumColumns; + public int mLeftKeys; + public int mRightKeys; // includes default key. + + public MiniKeyboardLayoutParams() { + super(); + } + + /* package for test */ MiniKeyboardLayoutParams(int numKeys, int maxColumns, int keyWidth, + int rowHeight, int coordXInParent, int parentKeyboardWidth) { + super(); + setParameters( + numKeys, maxColumns, keyWidth, rowHeight, coordXInParent, parentKeyboardWidth); + } /** - * The object holding mini keyboard layout parameters. + * Set keyboard parameters of mini keyboard. * * @param numKeys number of keys in this mini keyboard. * @param maxColumns number of maximum columns of this mini keyboard. @@ -54,15 +56,15 @@ public class MiniKeyboardBuilder { * @param rowHeight mini keyboard row height in pixel, including vertical gap. * @param coordXInParent coordinate x of the popup key in parent keyboard. * @param parentKeyboardWidth parent keyboard width in pixel. - * parent keyboard. */ - public MiniKeyboardLayoutParams(int numKeys, int maxColumns, int keyWidth, int rowHeight, + public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight, int coordXInParent, int parentKeyboardWidth) { - if (parentKeyboardWidth / keyWidth < maxColumns) + if (parentKeyboardWidth / keyWidth < maxColumns) { throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: " + parentKeyboardWidth + " " + keyWidth + " " + maxColumns); - mKeyWidth = keyWidth; - mRowHeight = rowHeight; + } + mDefaultKeyWidth = keyWidth; + mDefaultRowHeight = rowHeight; final int numRows = (numKeys + maxColumns - 1) / maxColumns; mNumRows = numRows; @@ -108,6 +110,9 @@ public class MiniKeyboardBuilder { } else { mTopRowAdjustment = -1; } + + mWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth; + mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap; } // Return key position according to column count (0 is default). @@ -160,19 +165,19 @@ public class MiniKeyboardBuilder { } public int getDefaultKeyCoordX() { - return mLeftKeys * mKeyWidth; + return mLeftKeys * mDefaultKeyWidth; } public int getX(int n, int row) { - final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX(); + final int x = getColumnPos(n) * mDefaultKeyWidth + getDefaultKeyCoordX(); if (isTopRow(row)) { - return x + mTopRowAdjustment * (mKeyWidth / 2); + return x + mTopRowAdjustment * (mDefaultKeyWidth / 2); } return x; } public int getY(int row) { - return (mNumRows - 1 - row) * mRowHeight + mTopPadding; + return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding; } public int getRowFlags(int row) { @@ -185,42 +190,32 @@ public class MiniKeyboardBuilder { private boolean isTopRow(int rowCount) { return rowCount == mNumRows - 1; } - - public void setTopPadding (int topPadding) { - mTopPadding = topPadding; - } - - public int getKeyboardHeight() { - return mNumRows * mRowHeight + mTopPadding; - } - - public int getKeyboardWidth() { - return mNumColumns * mKeyWidth; - } } - public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key parentKey, + public MiniKeyboardBuilder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) { - final Context context = view.getContext(); - mRes = context.getResources(); - final MiniKeyboard keyboard = new MiniKeyboard( - context, layoutTemplateResId, parentKeyboard); - mKeyboard = keyboard; + super(view.getContext(), new MiniKeyboardLayoutParams()); + load(parentKeyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId)); + + // HACK: Current mini keyboard design totally relies on the 9-patch padding about horizontal + // and vertical key spacing. To keep the visual of mini keyboard as is, these hacks are + // needed to keep having the same horizontal and vertical key spacing. + mParams.mHorizontalGap = 0; + mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2; + // TODO: When we have correctly padded key background 9-patch drawables for mini keyboard, + // revert the above hacks and uncomment the following lines. + //mParams.mHorizontalGap = parentKeyboard.mHorizontalGap; + //mParams.mVerticalGap = parentKeyboard.mVerticalGap; + + mParams.mIsRtlKeyboard = parentKeyboard.mIsRtlKeyboard; mPopupCharacters = parentKey.mPopupCharacters; - final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth()); - final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, mParams.mDefaultKeyWidth); + mParams.setParameters( mPopupCharacters.length, parentKey.mMaxPopupColumn, - keyWidth, parentKeyboard.getRowHeight(), - parentKey.mX + (parentKey.mWidth + parentKey.mGap) / 2 - keyWidth / 2, + keyWidth, parentKeyboard.mDefaultRowHeight, + parentKey.mX + (mParams.mDefaultKeyWidth - keyWidth) / 2, view.getMeasuredWidth()); - params.setTopPadding(keyboard.getVerticalGap()); - mParams = params; - - keyboard.setRowHeight(params.mRowHeight); - keyboard.setKeyboardHeight(params.getKeyboardHeight()); - keyboard.setMinWidth(params.getKeyboardWidth()); - keyboard.setDefaultCoordX(params.getDefaultKeyCoordX() + params.mKeyWidth / 2); } private static int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters, @@ -249,17 +244,16 @@ public class MiniKeyboardBuilder { return Math.max(minKeyWidth, maxWidth + horizontalPadding); } + @Override public MiniKeyboard build() { - final MiniKeyboard keyboard = mKeyboard; - final List<Key> keys = keyboard.getKeys(); final MiniKeyboardLayoutParams params = mParams; for (int n = 0; n < mPopupCharacters.length; n++) { final CharSequence label = mPopupCharacters[n]; final int row = n / params.mNumColumns; - final Key key = new Key(mRes, keyboard, label, params.getX(n, row), params.getY(row), - params.mKeyWidth, params.mRowHeight, params.getRowFlags(row)); - keys.add(key); + final Key key = new Key(mResources, params, label, params.getX(n, row), params.getY(row), + params.mDefaultKeyWidth, params.mDefaultRowHeight, params.getRowFlags(row)); + params.onAddKey(key); } - return keyboard; + return new MiniKeyboard(params); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java b/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java index 8276f5d78..032489e66 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PopupCharactersParser.java @@ -23,6 +23,8 @@ import android.util.Log; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.R; +import java.util.ArrayList; + /** * String parser of popupCharacters attribute of Key. * The string is comma separated texts each of which represents one popup key. @@ -182,4 +184,54 @@ public class PopupCharactersParser { super(message); } } + + public interface CodeFilter { + public boolean shouldFilterOut(int code); + } + + public static final CodeFilter DIGIT_FILTER = new CodeFilter() { + @Override + public boolean shouldFilterOut(int code) { + return Character.isDigit(code); + } + }; + + public static final CodeFilter NON_ASCII_FILTER = new CodeFilter() { + @Override + public boolean shouldFilterOut(int code) { + return code < 0x20 || code > 0x7e; + } + }; + + public static CharSequence[] filterOut(Resources res, CharSequence[] popupCharacters, + CodeFilter filter) { + if (popupCharacters == null || popupCharacters.length < 1) { + return null; + } + if (popupCharacters.length == 1 + && filter.shouldFilterOut(getCode(res, popupCharacters[0].toString()))) { + return null; + } + ArrayList<CharSequence> filtered = null; + for (int i = 0; i < popupCharacters.length; i++) { + final CharSequence popupSpec = popupCharacters[i]; + if (filter.shouldFilterOut(getCode(res, popupSpec.toString()))) { + if (filtered == null) { + filtered = new ArrayList<CharSequence>(); + for (int j = 0; j < i; j++) { + filtered.add(popupCharacters[j]); + } + } + } else if (filtered != null) { + filtered.add(popupSpec); + } + } + if (filtered == null) { + return popupCharacters; + } + if (filtered.size() == 0) { + return null; + } + return filtered.toArray(new CharSequence[filtered.size()]); + } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/Row.java b/java/src/com/android/inputmethod/keyboard/internal/Row.java index b34d6d06f..9299cc261 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/Row.java +++ b/java/src/com/android/inputmethod/keyboard/internal/Row.java @@ -31,34 +31,19 @@ import com.android.inputmethod.latin.R; */ public class Row { /** Default width of a key in this row. */ - public final int mDefaultWidth; + public final int mDefaultKeyWidth; /** Default height of a key in this row. */ - public final int mDefaultHeight; - /** Default horizontal gap between keys in this row. */ - public final int mDefaultHorizontalGap; - /** Vertical gap following this row. */ - public final int mVerticalGap; + public final int mRowHeight; - private final Keyboard mKeyboard; - - public Row(Resources res, Keyboard keyboard, XmlResourceParser parser) { - this.mKeyboard = keyboard; - final int keyboardWidth = keyboard.getDisplayWidth(); - final int keyboardHeight = keyboard.getKeyboardHeight(); + public Row(Resources res, KeyboardParams params, XmlResourceParser parser) { + final int keyboardWidth = params.mWidth; + final int keyboardHeight = params.mHeight; TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard); - mDefaultWidth = KeyboardParser.getDimensionOrFraction(a, - R.styleable.Keyboard_keyWidth, keyboardWidth, keyboard.getKeyWidth()); - mDefaultHeight = KeyboardParser.getDimensionOrFraction(a, - R.styleable.Keyboard_rowHeight, keyboardHeight, keyboard.getRowHeight()); - mDefaultHorizontalGap = KeyboardParser.getDimensionOrFraction(a, - R.styleable.Keyboard_horizontalGap, keyboardWidth, keyboard.getHorizontalGap()); - mVerticalGap = KeyboardParser.getDimensionOrFraction(a, - R.styleable.Keyboard_verticalGap, keyboardHeight, keyboard.getVerticalGap()); + mDefaultKeyWidth = KeyboardParser.getDimensionOrFraction(a, + R.styleable.Keyboard_keyWidth, keyboardWidth, params.mDefaultKeyWidth); + mRowHeight = KeyboardParser.getDimensionOrFraction(a, + R.styleable.Keyboard_rowHeight, keyboardHeight, params.mDefaultRowHeight); a.recycle(); } - - public Keyboard getKeyboard() { - return mKeyboard; - } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 97c222695..b2af6f9ee 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -789,7 +789,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final boolean selectionChanged = (newSelStart != candidatesEnd || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart; final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1; - if (((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars) + if (!mExpectingUpdateSelection + && ((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars) || mVoiceProxy.isVoiceInputHighlighted()) && (selectionChanged || candidatesCleared)) { if (candidatesCleared) { @@ -1684,7 +1685,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final int rawPrimaryCode = suggestion.charAt(0); // Maybe apply the "bidi mirrored" conversions for parentheses final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard(); - final int primaryCode = keyboard.isRtlKeyboard() + final int primaryCode = keyboard.mIsRtlKeyboard ? Key.getRtlParenthesisCode(rawPrimaryCode) : rawPrimaryCode; final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : ""; |