From 8da9a13760896cd78235b60d0ea680ea13620532 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 28 Jul 2011 17:05:40 -0700 Subject: [PATCH] Make Keyboard object immutable except shift state This is the first step to implement suggestions pane as mini keyboard. Bug: 5023981 Change-Id: I90ffbde0fda19b4be68add449310997b56bf6904 --- java/proguard.flags | 4 + .../com/android/inputmethod/keyboard/Key.java | 47 ++- .../inputmethod/keyboard/KeyDetector.java | 2 +- .../inputmethod/keyboard/Keyboard.java | 269 +++--------------- .../inputmethod/keyboard/KeyboardId.java | 12 +- .../keyboard/KeyboardSwitcher.java | 14 +- .../inputmethod/keyboard/KeyboardView.java | 4 +- .../inputmethod/keyboard/LatinKeyboard.java | 67 +++-- .../keyboard/LatinKeyboardBaseView.java | 4 +- .../keyboard/LatinKeyboardView.java | 2 +- .../inputmethod/keyboard/MiniKeyboard.java | 26 +- .../inputmethod/keyboard/PointerTracker.java | 2 +- .../keyboard/PopupMiniKeyboardView.java | 8 +- .../keyboard/internal/KeyboardParams.java | 51 ++-- .../keyboard/internal/KeyboardParser.java | 216 +++++++------- .../internal/MiniKeyboardBuilder.java | 118 ++++---- .../inputmethod/keyboard/internal/Row.java | 25 +- .../android/inputmethod/latin/LatinIME.java | 2 +- .../inputmethod/latin/SuggestHelper.java | 6 +- 19 files changed, 345 insertions(+), 534 deletions(-) diff --git a/java/proguard.flags b/java/proguard.flags index 7ce6f41b5..44416ecba 100644 --- a/java/proguard.flags +++ b/java/proguard.flags @@ -30,3 +30,7 @@ -keep class com.android.inputmethod.latin.SettingsActivity { *; } + +-keep class com.android.inputmethod.keyboard.internal.MiniKeyboardBuilder$MiniKeyboardLayoutParams { + (...); +} diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index a4aa0c1ea..8bc7e43b4 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -27,6 +27,7 @@ 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; @@ -190,11 +191,11 @@ 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) { - mHeight = height - keyboard.getVerticalGap(); - mHorizontalGap = keyboard.getHorizontalGap(); - mVerticalGap = keyboard.getVerticalGap(); + mHeight = height - params.mVerticalGap; + mHorizontalGap = params.mHorizontalGap; + mVerticalGap = params.mVerticalGap; mVisualInsetsLeft = mVisualInsetsRight = 0; mWidth = width - mHorizontalGap; mEdgeFlags = edgeFlags; @@ -209,8 +210,8 @@ 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 + mHorizontalGap / 2; mY = y; @@ -220,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) { - final Keyboard keyboard = 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); @@ -237,14 +237,14 @@ public class Key { try { mHeight = KeyboardParser.getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_rowHeight, - keyboard.getKeyboardHeight(), row.mDefaultHeight) - keyboard.getVerticalGap(); + params.mHeight, row.mRowHeight) - params.mVerticalGap; mHorizontalGap = KeyboardParser.getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_horizontalGap, - keyboard.getDisplayWidth(), keyboard.getHorizontalGap()); - mVerticalGap = keyboard.getVerticalGap(); + params.mWidth, params.mHorizontalGap); + mVerticalGap = params.mVerticalGap; keyWidth = KeyboardParser.getDimensionOrFraction(keyboardAttr, R.styleable.Keyboard_keyWidth, - keyboard.getDisplayWidth(), row.mDefaultWidth); + params.mWidth, row.mDefaultKeyWidth); } finally { keyboardAttr.recycle(); } @@ -262,7 +262,7 @@ public class Key { style = keyStyles.getEmptyKeyStyle(); } - final int keyboardWidth = keyboard.getDisplayWidth(); + final int keyboardWidth = params.mOccupiedWidth; int keyXPos = KeyboardParser.getDimensionOrFraction(keyAttr, R.styleable.Keyboard_Key_keyXPos, keyboardWidth, x); if (keyXPos < 0) { @@ -293,13 +293,13 @@ public class Key { CharSequence[] popupCharacters = style.getTextArray( keyAttr, R.styleable.Keyboard_Key_popupCharacters); - if (keyboard.mId.mPasswordInput) { + 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 (keyboard.mId.isAlphabetKeyboard() && !res.getBoolean( + if (params.mId.isAlphabetKeyboard() && !res.getBoolean( R.bool.config_digit_popup_characters_enabled)) { mPopupCharacters = PopupCharactersParser.filterOut( res, popupCharacters, PopupCharactersParser.DIGIT_FILTER); @@ -308,7 +308,7 @@ public class Key { } mMaxPopupColumn = style.getInt(keyboardAttr, R.styleable.Keyboard_Key_maxPopupKeyboardColumn, - keyboard.getMaxPopupKeyboardColumn()); + params.mMaxPopupColumn); mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false); mFunctional = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isFunctional, false); @@ -316,7 +316,7 @@ public class Key { mEnabled = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_enabled, true); mEdgeFlags = 0; - final KeyboardIconsSet iconsSet = keyboard.mIconsSet; + final KeyboardIconsSet iconsSet = params.mIconsSet; mVisualInsetsLeft = KeyboardParser.getDimensionOrFraction(keyAttr, R.styleable.Keyboard_Key_visualInsetsLeft, keyboardWidth, 0); mVisualInsetsRight = KeyboardParser.getDimensionOrFraction(keyAttr, @@ -331,7 +331,7 @@ public class Key { KeyboardIconsSet.ICON_UNDEFINED); if (shiftedIconId != KeyboardIconsSet.ICON_UNDEFINED) { final Drawable shiftedIcon = iconsSet.getIcon(shiftedIconId); - keyboard.addShiftedIcon(this, shiftedIcon); + params.addShiftedIcon(this, shiftedIcon); } mHintLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel); @@ -344,15 +344,12 @@ public class Key { Keyboard.CODE_UNSPECIFIED); if (code == Keyboard.CODE_UNSPECIFIED && !TextUtils.isEmpty(mLabel)) { final int firstChar = mLabel.charAt(0); - mCode = keyboard.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) { - keyboard.addShiftKey(this); - } } finally { keyAttr.recycle(); } 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 ae5bc95ee..809c949df 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -16,23 +16,14 @@ 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; @@ -56,8 +47,6 @@ import java.util.Set; * */ 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; @@ -98,209 +87,77 @@ public class Keyboard { public final KeyboardId mId; /** Total height of the keyboard, including the padding and keys */ - private int mTotalHeight; + public final int mOccupiedHeight; + /** Total width of the keyboard, including the padding and keys */ + public final int mOccupiedWidth; - /** - * Total width (minimum width) of the keyboard, including left side gaps and keys, but not any - * gaps on the right side. - */ - private int mMinWidth; - - /** Horizontal gap default for all rows */ - private int mHorizontalGap; - - /** Default key width */ - private int mDefaultKeyWidth; + public final int mHeight; + public final int mWidth; /** Default row height */ - private int mDefaultRowHeight; + public final int mDefaultRowHeight; /** Default gap between rows */ - private int mVerticalGap; + 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; + public final boolean mIsRtlKeyboard; - /** List of keys in this keyboard */ - private final List mKeys = new ArrayList(); - /** List of shift keys in this keyboard and its icons and state */ - private final List mShiftKeys = new ArrayList(); - private final Map mShiftedIcons = new HashMap(); - private final Map mUnshiftedIcons = new HashMap(); - private final Set mShiftLockKeys = new HashSet(); - public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); - - - /** 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; - - private int mMostCommonKeyWidth = 0; + /** List of keys and icons in this keyboard */ + public final List mKeys; + public final List mShiftKeys; + public final Set mShiftLockKeys; + public final Map mShiftedIcons; + public final Map mUnshiftedIcons; + public final KeyboardIconsSet mIconsSet; private final KeyboardShiftState mShiftState = new KeyboardShiftState(); - // 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 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; - 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); + mDefaultRowHeight = params.mDefaultRowHeight; + mVerticalGap = params.mVerticalGap; - 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; + 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; - mHorizontalGap = 0; - setKeyWidth(mDisplayWidth / 10); - mVerticalGap = 0; - mDefaultRowHeight = mDefaultKeyWidth; - 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 getKeys() { return mKeys; } - public int getHorizontalGap() { - return mHorizontalGap; - } - - public void setHorizontalGap(int gap) { - mHorizontalGap = gap; - } - - public int getVerticalGap() { - return mVerticalGap; - } - - public void setVerticalGap(int gap) { - mVerticalGap = gap; - } - - public int getRowHeight() { - return mDefaultRowHeight; - } - - public void setRowHeight(int height) { - mDefaultRowHeight = height; - } - - public int getKeyWidth() { - return mDefaultKeyWidth; - } - - public void setKeyWidth(int width) { - mDefaultKeyWidth = 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(); } @@ -391,46 +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 histogram = new HashMap(); - int maxCount = 0; - int mostCommonWidth = 0; - for (final Key key : mKeys) { - final Integer width = key.mWidth + key.mHorizontalGap; - 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); - } - } } 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(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 e23725818..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); 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 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 { + 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/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java index 58d742003..4ccaa72d2 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java @@ -19,6 +19,7 @@ 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; @@ -31,8 +32,8 @@ import java.util.Set; public class KeyboardParams { public KeyboardId mId; - public int mTotalHeight; - public int mTotalWidth; + public int mOccupiedHeight; + public int mOccupiedWidth; public int mHeight; public int mWidth; @@ -61,40 +62,34 @@ public class KeyboardParams { public final Map mUnshiftedIcons = new HashMap(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); - public void addShiftKey(Key key) { - if (key == null) return; - mShiftKeys.add(key); - if (key.mSticky) { - mShiftLockKeys.add(key); + 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) { - if (key == null) return; mUnshiftedIcons.put(key, key.getIcon()); mShiftedIcons.put(key, icon); } - /** - * 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() { - final HashMap histogram = new HashMap(); - int maxCount = 0; - int mostCommonWidth = 0; - for (final Key key : mKeys) { - final Integer width = key.mWidth + key.mHorizontalGap; - Integer count = histogram.get(width); - if (count == null) - count = 0; - histogram.put(width, ++count); - if (count > maxCount) { - maxCount = count; - mostCommonWidth = width; - } + private int mMaxCount = 0; + private final Map mHistogram = new HashMap(); + + 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; } - return mostCommonWidth; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParser.java index e3238c30c..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; * */ -public class KeyboardParser { +public class KeyboardParser { 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 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,37 +231,41 @@ 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); + 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); - 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)); + 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); - mKeyboard.mIconsSet.loadIcons(keyboardAttr); - mKeyboardTopPadding = getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_keyboardTopPadding, height, 0); - mKeyboardBottomPadding = getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_keyboardBottomPadding, 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 keys) + private void parseKeyboardContent(XmlResourceParser parser, boolean skip) throws XmlPullParserException, IOException { int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -258,22 +274,22 @@ public class KeyboardParser { if (TAG_ROW.equals(tag)) { 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)) { @@ -296,28 +312,28 @@ public class KeyboardParser { throw new IllegalAttribute(parser, "horizontalGap"); if (a.hasValue(R.styleable.Keyboard_verticalGap)) throw new IllegalAttribute(parser, "verticalGap"); - return new Row(mResources, mKeyboard, parser); + return new Row(mResources, mParams, parser); } finally { a.recycle(); } } - private void parseRowContent(XmlResourceParser parser, Row row, List keys) + 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); } @@ -325,7 +341,7 @@ public class KeyboardParser { final String tag = parser.getName(); if (TAG_ROW.equals(tag)) { if (DEBUG) Log.d(TAG, String.format("", TAG_ROW)); - if (keys != null) + if (!skip) endRow(); break; } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) @@ -341,24 +357,24 @@ public class KeyboardParser { } } - private void parseKey(XmlResourceParser parser, Row row, List 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 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)); @@ -366,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), @@ -385,19 +401,19 @@ public class KeyboardParser { } } - private void parseIncludeKeyboardContent(XmlResourceParser parser, List 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 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 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), @@ -411,11 +427,11 @@ public class KeyboardParser { throw new ParseException("No keyboardLayout attribute in ", 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 keys) + private void parseMerge(XmlResourceParser parser, Row row, boolean skip) throws XmlPullParserException, IOException { int event; while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -423,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 { @@ -436,28 +452,28 @@ public class KeyboardParser { } } - private void parseSwitchKeyboardContent(XmlResourceParser parser, List 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 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 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); } @@ -473,21 +489,21 @@ public class KeyboardParser { } } - private boolean parseCase(XmlResourceParser parser, Row row, List 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; @@ -596,18 +612,18 @@ public class KeyboardParser { return false; } - private boolean parseDefault(XmlResourceParser parser, Row row, List 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 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), @@ -616,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(); @@ -632,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; @@ -650,10 +666,8 @@ 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; } @@ -666,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 58862f8b5..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 { 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.mHorizontalGap) / 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 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/Row.java b/java/src/com/android/inputmethod/keyboard/internal/Row.java index 34b8d91b9..9299cc261 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/Row.java +++ b/java/src/com/android/inputmethod/keyboard/internal/Row.java @@ -31,26 +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; + 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()); + 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 bdcbfbcb1..b2af6f9ee 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1685,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) : ""; diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java index 07d0e5d75..f9ea1805a 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java @@ -36,7 +36,7 @@ public class SuggestHelper { // Use null as the locale for Suggest so as to force it to use the internal dictionary // (and not try to find a dictionary provider for a specified locale) mSuggest = new Suggest(context, dictionaryId, null); - mKeyboard = new LatinKeyboard(context, keyboardId, keyboardId.mWidth); + mKeyboard = new LatinKeyboard.Builder(context).load(keyboardId).build(); mKeyDetector = new KeyDetector(0); init(); } @@ -44,7 +44,7 @@ public class SuggestHelper { protected SuggestHelper(Context context, File dictionaryPath, long startOffset, long length, KeyboardId keyboardId) { mSuggest = new Suggest(context, dictionaryPath, startOffset, length, null); - mKeyboard = new LatinKeyboard(context, keyboardId, keyboardId.mWidth); + mKeyboard = new LatinKeyboard.Builder(context).load(keyboardId).build(); mKeyDetector = new KeyDetector(0); init(); } @@ -54,7 +54,7 @@ public class SuggestHelper { mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL); mKeyDetector.setKeyboard(mKeyboard, 0, 0); mKeyDetector.setProximityCorrectionEnabled(true); - mKeyDetector.setProximityThreshold(mKeyboard.getMostCommonKeyWidth()); + mKeyDetector.setProximityThreshold(mKeyboard.mMostCommonKeyWidth); } public void setCorrectionMode(int correctionMode) {