From 04c96ab966e8a58e5cd401362b49509751ce75d9 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 19 Jan 2011 20:59:57 +0900 Subject: [PATCH] Automatically layout mini keyboard Bug: 2214959 Change-Id: I06370e1c9e0683666ad19454a2fb501008af95c0 --- .../res/values-cs/donottranslate-altchars.xml | 10 +- .../res/values-da/donottranslate-altchars.xml | 12 +- .../res/values-de/donottranslate-altchars.xml | 2 +- .../res/values-en/donottranslate-altchars.xml | 6 +- .../res/values-es/donottranslate-altchars.xml | 2 +- .../res/values-it/donottranslate-altchars.xml | 2 +- .../res/values-nb/donottranslate-altchars.xml | 10 +- .../res/values-pl/donottranslate-altchars.xml | 4 +- .../res/values-rm/donottranslate-altchars.xml | 2 +- .../res/values-ru/donottranslate-altchars.xml | 2 +- .../res/values-sv/donottranslate-altchars.xml | 12 +- .../res/values-tr/donottranslate-altchars.xml | 4 +- java/res/values-xlarge/config.xml | 4 +- java/res/values/config.xml | 4 +- java/res/values/donottranslate-altchars.xml | 8 +- .../inputmethod/keyboard/KeyboardView.java | 138 +++----- .../keyboard/LatinKeyboardView.java | 4 +- .../inputmethod/keyboard/MiniKeyboard.java | 35 ++ .../keyboard/MiniKeyboardBuilder.java | 201 +++++++---- .../keyboard/MiniKeyboardBuilderTests.java | 312 ++++++++++++++++++ 20 files changed, 578 insertions(+), 196 deletions(-) create mode 100644 java/src/com/android/inputmethod/keyboard/MiniKeyboard.java create mode 100644 tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java diff --git a/java/res/values-cs/donottranslate-altchars.xml b/java/res/values-cs/donottranslate-altchars.xml index f19ac0026..8440d6932 100644 --- a/java/res/values-cs/donottranslate-altchars.xml +++ b/java/res/values-cs/donottranslate-altchars.xml @@ -20,14 +20,14 @@ á,à,â,ã,ä,å,æ 3,é,ě,è,ê,ë - í,ì,î,ï,8 - ó,ò,ô,õ,ö,œ,ø,9 - ů,ú,ù,û,ü,7 + 8,í,ì,î,ï + 9,ó,ò,ô,õ,ö,œ,ø + 7,ů,ú,ù,û,ü š,§,ß ň,ñ č,ç ď - ř,4 - ť,5 + 4,ř + 5,ť ž diff --git a/java/res/values-da/donottranslate-altchars.xml b/java/res/values-da/donottranslate-altchars.xml index ca1df7c25..09c264e87 100644 --- a/java/res/values-da/donottranslate-altchars.xml +++ b/java/res/values-da/donottranslate-altchars.xml @@ -20,16 +20,16 @@ á,à,â,ą,ã 3,é,è,ê,ë,ę,€ - í,ì,î,ï,8 - ó,ò,ô,õ,9 - ú,ù,û,ū,7 + 8,í,ì,î,ï + 9,ó,ò,ô,õ + 7,ú,ù,û,ū ś,š,ş,ß ń,ñ,ň ç,ć,č - ý,ÿ,ü,6 + 6,ý,ÿ,ü ð,ď - ř,4 - ť,þ,5 + 4,ř + 5,ť,þ ź,ž,ż ł w diff --git a/java/res/values-de/donottranslate-altchars.xml b/java/res/values-de/donottranslate-altchars.xml index 6c1abc6d0..141ad8433 100644 --- a/java/res/values-de/donottranslate-altchars.xml +++ b/java/res/values-de/donottranslate-altchars.xml @@ -19,7 +19,7 @@ --> ä - ö,9 + 9,ö ý,ÿ 6 diff --git a/java/res/values-en/donottranslate-altchars.xml b/java/res/values-en/donottranslate-altchars.xml index baded885a..a564a8c0c 100644 --- a/java/res/values-en/donottranslate-altchars.xml +++ b/java/res/values-en/donottranslate-altchars.xml @@ -20,7 +20,7 @@ à,á,â,ã,ä,å,ā,æ 3,è,é,ê,ë,ē - ì,í,î,ï,ī,8 - ò,ó,ô,õ,ö,ō,œ,ø,9 - ù,ú,û,ü,ū,7 + 8,ì,í,î,ï,ī + 9,ò,ó,ô,õ,ö,ō,œ,ø + 7,ù,ú,û,ü,ū diff --git a/java/res/values-es/donottranslate-altchars.xml b/java/res/values-es/donottranslate-altchars.xml index 35187d0de..65d5c1153 100644 --- a/java/res/values-es/donottranslate-altchars.xml +++ b/java/res/values-es/donottranslate-altchars.xml @@ -20,5 +20,5 @@ á 3,é - ó,9 + 9,ó diff --git a/java/res/values-it/donottranslate-altchars.xml b/java/res/values-it/donottranslate-altchars.xml index 0e4a285f1..1c3dc7e32 100644 --- a/java/res/values-it/donottranslate-altchars.xml +++ b/java/res/values-it/donottranslate-altchars.xml @@ -20,6 +20,6 @@ à,á 3,è,é - ò,ó,9 + 9,ò,ó § diff --git a/java/res/values-nb/donottranslate-altchars.xml b/java/res/values-nb/donottranslate-altchars.xml index c65dea9fb..91f8b21dc 100644 --- a/java/res/values-nb/donottranslate-altchars.xml +++ b/java/res/values-nb/donottranslate-altchars.xml @@ -20,15 +20,15 @@ ä,á,à,â,ą,ã 3,é,è,ê,ë,ę,€ - í,ì,î,ï,8 - ö,ó,ò,ô,õ,9 - ü,ú,ù,û,ū,7 + 8,í,ì,î,ï + 9,ö,ó,ò,ô,õ + 7,ü,ú,ù,û,ū ś,š,ş,ß ń,ñ,ň ç,ć,č ð,ď - ř,4 - ť,þ,5 + 4,ř + 5,ť,þ ź,ž,ż ł w diff --git a/java/res/values-pl/donottranslate-altchars.xml b/java/res/values-pl/donottranslate-altchars.xml index df8c52b47..ac099028d 100644 --- a/java/res/values-pl/donottranslate-altchars.xml +++ b/java/res/values-pl/donottranslate-altchars.xml @@ -19,8 +19,8 @@ --> ą - ę,3 - ó,9 + 3,ę + 9,ó ś ń ć diff --git a/java/res/values-rm/donottranslate-altchars.xml b/java/res/values-rm/donottranslate-altchars.xml index b44c3c005..0a5d2aad1 100644 --- a/java/res/values-rm/donottranslate-altchars.xml +++ b/java/res/values-rm/donottranslate-altchars.xml @@ -18,5 +18,5 @@ */ --> - ò,ó,ö,ô,õ,œ,ø,9 + 9,ò,ó,ö,ô,õ,œ,ø diff --git a/java/res/values-ru/donottranslate-altchars.xml b/java/res/values-ru/donottranslate-altchars.xml index c4f9d66d3..2da8b8469 100644 --- a/java/res/values-ru/donottranslate-altchars.xml +++ b/java/res/values-ru/donottranslate-altchars.xml @@ -18,6 +18,6 @@ */ --> - ё5 + 5,ё ъ diff --git a/java/res/values-sv/donottranslate-altchars.xml b/java/res/values-sv/donottranslate-altchars.xml index e156de896..46b3803db 100644 --- a/java/res/values-sv/donottranslate-altchars.xml +++ b/java/res/values-sv/donottranslate-altchars.xml @@ -20,16 +20,16 @@ á,à,â,ą,ã 3,é,è,ê,ë,ę,€ - í,ì,î,ï,8 - ó,ò,ô,õ,9 - ú,ù,û,ū,7 + 8,í,ì,î,ï + 9,ó,ò,ô,õ + 7,ú,ù,û,ū ś,š,ş,ß ń,ñ,ň ç,ć,č - ý,ÿ,ü,6 + 6,ý,ÿ,ü ð,ď - ř,4 - ť,þ,5 + 4,ř + 5,ť,þ ź,ž,ż ł w diff --git a/java/res/values-tr/donottranslate-altchars.xml b/java/res/values-tr/donottranslate-altchars.xml index 5e98cc30e..1378fa90b 100644 --- a/java/res/values-tr/donottranslate-altchars.xml +++ b/java/res/values-tr/donottranslate-altchars.xml @@ -18,8 +18,8 @@ */ --> - ö,ò,ó,ô,õ,œ,ø,9 - ü,ù,ú,û,7 + 9,ö,ò,ó,ô,õ,œ,ø + 7,ü,ù,ú,û ş,§,ß ğ diff --git a/java/res/values-xlarge/config.xml b/java/res/values-xlarge/config.xml index 004b39b92..40fdce0fd 100644 --- a/java/res/values-xlarge/config.xml +++ b/java/res/values-xlarge/config.xml @@ -33,10 +33,12 @@ false false + + true 1200 5 medium - 9 + 5 diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 6a1b27a05..ceb4f1252 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -40,6 +40,8 @@ true true true + + false -1 50 @@ -61,7 +63,7 @@ 4 small - 9 + 10 true diff --git a/java/res/values/donottranslate-altchars.xml b/java/res/values/donottranslate-altchars.xml index 85e06f23b..c5a369f9c 100644 --- a/java/res/values/donottranslate-altchars.xml +++ b/java/res/values/donottranslate-altchars.xml @@ -20,13 +20,13 @@ à,á,â,ã,ä,å,æ 3,è,é,ê,ë - ì,í,î,ï,8 - ò,ó,ô,õ,ö,œ,ø,9 - ù,ú,û,ü,7 + 8,ì,í,î,ï + 9,ò,ó,ô,õ,ö,œ,ø + 7,ù,ú,û,ü §,ß ñ ç - ý,ÿ,6 + 6,ý,ÿ 1 2 diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 766fdf0e6..6d7bfb8d5 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -125,7 +125,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Popup mini keyboard private PopupWindow mMiniKeyboardPopup; - private KeyboardView mMiniKeyboard; + private KeyboardView mMiniKeyboardView; private View mMiniKeyboardParent; private final WeakHashMap mMiniKeyboardCache = new WeakHashMap(); private int mMiniKeyboardOriginX; @@ -134,6 +134,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { private int[] mWindowOffset; private final float mMiniKeyboardSlideAllowance; private int mMiniKeyboardTrackerId; + private final boolean mConfigShowMiniKeyboardAtTouchedPoint; /** Listener for {@link KeyboardActionListener}. */ private KeyboardActionListener mKeyboardActionListener; @@ -296,7 +297,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { public KeyboardView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - TypedArray a = context.obtainStyledAttributes( + final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); int previewLayout = 0; int keyTextSize = 0; @@ -381,6 +382,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mMiniKeyboardPopup = new PopupWindow(context); mMiniKeyboardPopup.setBackgroundDrawable(null); mMiniKeyboardPopup.setAnimationStyle(R.style.MiniKeyboardAnimation); + // Allow popup window to be drawn off the screen. + mMiniKeyboardPopup.setClippingEnabled(false); mPaint = new Paint(); mPaint.setAntiAlias(true); @@ -395,6 +398,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // TODO: Refer frameworks/base/core/res/res/values/config.xml mDisambiguateSwipe = res.getBoolean(R.bool.config_swipeDisambiguation); mMiniKeyboardSlideAllowance = res.getDimension(R.dimen.mini_keyboard_slide_allowance); + mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean( + R.bool.config_show_mini_keyboard_at_touched_point); GestureDetector.SimpleOnGestureListener listener = new GestureDetector.SimpleOnGestureListener() { @@ -535,10 +540,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { return mColorScheme; } - public void setPopupParent(View v) { - mMiniKeyboardParent = v; - } - public void setPopupOffset(int x, int y) { mPopupPreviewOffsetX = x; mPopupPreviewOffsetY = y; @@ -798,7 +799,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mInvalidatedKey = null; // Overlay a dark rectangle to dim the keyboard - if (mMiniKeyboard != null) { + if (mMiniKeyboardView != null) { paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); canvas.drawRect(0, 0, getWidth(), getHeight(), paint); } @@ -1052,7 +1053,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { Key popupKey = tracker.getKey(keyIndex); if (popupKey == null) return false; - boolean result = onLongPress(popupKey); + boolean result = onLongPress(popupKey, tracker); if (result) { dismissKeyPreview(); mMiniKeyboardTrackerId = tracker.mPointerId; @@ -1077,14 +1078,13 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } private View inflateMiniKeyboardContainer(Key popupKey) { - int popupKeyboardResId = mKeyboard.getPopupKeyboardResId(); - View container = LayoutInflater.from(getContext()).inflate(mPopupLayout, null); + final View container = LayoutInflater.from(getContext()).inflate(mPopupLayout, null); if (container == null) throw new NullPointerException(); - KeyboardView miniKeyboard = + final KeyboardView miniKeyboardView = (KeyboardView)container.findViewById(R.id.KeyboardView); - miniKeyboard.setOnKeyboardActionListener(new KeyboardActionListener() { + miniKeyboardView.setOnKeyboardActionListener(new KeyboardActionListener() { @Override public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { mKeyboardActionListener.onCodeInput(primaryCode, keyCodes, x, y); @@ -1117,14 +1117,14 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } }); // Override default ProximityKeyDetector. - miniKeyboard.mKeyDetector = new MiniKeyboardKeyDetector(mMiniKeyboardSlideAllowance); + miniKeyboardView.mKeyDetector = new MiniKeyboardKeyDetector(mMiniKeyboardSlideAllowance); // Remove gesture detector on mini-keyboard - miniKeyboard.mGestureDetector = null; + miniKeyboardView.mGestureDetector = null; - Keyboard keyboard = new MiniKeyboardBuilder(this, popupKeyboardResId, popupKey) - .build(); - miniKeyboard.setKeyboard(keyboard); - miniKeyboard.setPopupParent(this); + final Keyboard keyboard = new MiniKeyboardBuilder(this, mKeyboard.getPopupKeyboardResId(), + popupKey).build(); + miniKeyboardView.setKeyboard(keyboard); + miniKeyboardView.mMiniKeyboardParent = this; container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); @@ -1152,7 +1152,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { * @return true if the long press is handled, false otherwise. Subclasses should call the * method on the base class if the subclass doesn't wish to handle the call. */ - protected boolean onLongPress(Key popupKey) { + protected boolean onLongPress(Key popupKey, PointerTracker tracker) { if (popupKey.mPopupCharacters == null) return false; @@ -1161,93 +1161,51 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { container = inflateMiniKeyboardContainer(popupKey); mMiniKeyboardCache.put(popupKey, container); } - mMiniKeyboard = (KeyboardView)container.findViewById(R.id.KeyboardView); + mMiniKeyboardView = (KeyboardView)container.findViewById(R.id.KeyboardView); + final MiniKeyboard miniKeyboard = (MiniKeyboard)mMiniKeyboardView.getKeyboard(); + if (mWindowOffset == null) { mWindowOffset = new int[2]; getLocationInWindow(mWindowOffset); } - - // Get width of a key in the mini popup keyboard = "miniKeyWidth". - // On the other hand, "popupKey.width" is width of the pressed key on the main keyboard. - // We adjust the position of mini popup keyboard with the edge key in it: - // a) When we have the leftmost key in popup keyboard directly above the pressed key - // Right edges of both keys should be aligned for consistent default selection - // b) When we have the rightmost key in popup keyboard directly above the pressed key - // Left edges of both keys should be aligned for consistent default selection - final List miniKeys = mMiniKeyboard.getKeyboard().getKeys(); - final int miniKeyWidth = miniKeys.size() > 0 ? miniKeys.get(0).mWidth : 0; - - // HACK: Have the leftmost number in the popup characters right above the key - boolean isNumberAtLeftmost = - hasMultiplePopupChars(popupKey) && isNumberAtLeftmostPopupChar(popupKey); - int popupX = popupKey.mX + mWindowOffset[0]; - popupX += getPaddingLeft(); - if (isNumberAtLeftmost) { - popupX += popupKey.mWidth - miniKeyWidth; // adjustment for a) described above - popupX -= container.getPaddingLeft(); - } else { - popupX += miniKeyWidth; // adjustment for b) described above - popupX -= container.getMeasuredWidth(); - popupX += container.getPaddingRight(); - } - int popupY = popupKey.mY + mWindowOffset[1]; - popupY += getPaddingTop(); - popupY -= container.getMeasuredHeight(); - popupY += container.getPaddingBottom(); + final int pointX = (mConfigShowMiniKeyboardAtTouchedPoint) ? tracker.getLastX() + : popupKey.mX + popupKey.mWidth / 2; + final int popupX = pointX - miniKeyboard.getDefaultCoordX() + - container.getPaddingLeft() + + getPaddingLeft() + mWindowOffset[0]; + final int popupY = popupKey.mY - mKeyboard.getVerticalGap() + - (container.getMeasuredHeight() - container.getPaddingBottom()) + + getPaddingTop() + mWindowOffset[1]; final int x = popupX; - final int y = mShowPreview && isOneRowKeys(miniKeys) ? mPopupPreviewDisplayedY : popupY; + final int y = mShowPreview && isOneRowKeys(miniKeyboard.getKeys()) + ? mPopupPreviewDisplayedY : popupY; - int adjustedX = x; - if (x < 0) { - adjustedX = 0; - } else if (x > (getMeasuredWidth() - container.getMeasuredWidth())) { - adjustedX = getMeasuredWidth() - container.getMeasuredWidth(); - } - mMiniKeyboardOriginX = adjustedX + container.getPaddingLeft() - mWindowOffset[0]; + mMiniKeyboardOriginX = x + container.getPaddingLeft() - mWindowOffset[0]; mMiniKeyboardOriginY = y + container.getPaddingTop() - mWindowOffset[1]; - mMiniKeyboard.setPopupOffset(adjustedX, y); - Keyboard baseMiniKeyboard = mMiniKeyboard.getKeyboard(); - if (baseMiniKeyboard != null && baseMiniKeyboard.setShifted(mKeyboard == null - ? false : mKeyboard.isShiftedOrShiftLocked())) { - mMiniKeyboard.invalidateAllKeys(); + mMiniKeyboardView.setPopupOffset(x, y); + if (miniKeyboard.setShifted( + mKeyboard == null ? false : mKeyboard.isShiftedOrShiftLocked())) { + mMiniKeyboardView.invalidateAllKeys(); } // Mini keyboard needs no pop-up key preview displayed. - mMiniKeyboard.setPreviewEnabled(false); + mMiniKeyboardView.setPreviewEnabled(false); mMiniKeyboardPopup.setContentView(container); mMiniKeyboardPopup.setWidth(container.getMeasuredWidth()); mMiniKeyboardPopup.setHeight(container.getMeasuredHeight()); mMiniKeyboardPopup.showAtLocation(this, Gravity.NO_GRAVITY, x, y); // Inject down event on the key to mini keyboard. - long eventTime = SystemClock.uptimeMillis(); + final long eventTime = SystemClock.uptimeMillis(); mMiniKeyboardPopupTime = eventTime; - MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, popupKey.mX - + popupKey.mWidth / 2, popupKey.mY + popupKey.mHeight / 2, eventTime); - mMiniKeyboard.onTouchEvent(downEvent); + final MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, + pointX, popupKey.mY + popupKey.mHeight / 2, eventTime); + mMiniKeyboardView.onTouchEvent(downEvent); downEvent.recycle(); invalidateAllKeys(); return true; } - private static boolean hasMultiplePopupChars(Key key) { - if (key.mPopupCharacters != null && key.mPopupCharacters.length > 1) { - return true; - } - return false; - } - - private static boolean isNumberAtLeftmostPopupChar(Key key) { - if (key.mPopupCharacters != null && isAsciiDigit(key.mPopupCharacters[0].charAt(0))) { - return true; - } - return false; - } - - private static boolean isAsciiDigit(char c) { - return (c < 0x80) && Character.isDigit(c); - } - private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) { return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action, x - mMiniKeyboardOriginX, y - mMiniKeyboardOriginY, 0); @@ -1273,8 +1231,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { } public boolean isInSlidingKeyInput() { - if (mMiniKeyboard != null) { - return mMiniKeyboard.isInSlidingKeyInput(); + if (mMiniKeyboardView != null) { + return mMiniKeyboardView.isInSlidingKeyInput(); } else { return mPointerQueue.isInSlidingKeyInput(); } @@ -1302,7 +1260,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mSwipeTracker.addMovement(me); // Gesture detector must be enabled only when mini-keyboard is not on the screen. - if (mMiniKeyboard == null + if (mMiniKeyboardView == null && mGestureDetector != null && mGestureDetector.onTouchEvent(me)) { dismissKeyPreview(); mHandler.cancelKeyTimers(); @@ -1317,14 +1275,14 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { // Needs to be called after the gesture detector gets a turn, as it may have // displayed the mini keyboard - if (mMiniKeyboard != null) { + if (mMiniKeyboardView != null) { final int miniKeyboardPointerIndex = me.findPointerIndex(mMiniKeyboardTrackerId); if (miniKeyboardPointerIndex >= 0 && miniKeyboardPointerIndex < pointerCount) { final int miniKeyboardX = (int)me.getX(miniKeyboardPointerIndex); final int miniKeyboardY = (int)me.getY(miniKeyboardPointerIndex); MotionEvent translated = generateMiniKeyboardMotionEvent(action, miniKeyboardX, miniKeyboardY, eventTime); - mMiniKeyboard.onTouchEvent(translated); + mMiniKeyboardView.onTouchEvent(translated); translated.recycle(); } return true; @@ -1422,7 +1380,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { private void dismissPopupKeyboard() { if (mMiniKeyboardPopup.isShowing()) { mMiniKeyboardPopup.dismiss(); - mMiniKeyboard = null; + mMiniKeyboardView = null; mMiniKeyboardOriginX = 0; mMiniKeyboardOriginY = 0; invalidateAllKeys(); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index e9d5580e8..94294e40a 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -94,7 +94,7 @@ public class LatinKeyboardView extends KeyboardView { } @Override - protected boolean onLongPress(Key key) { + protected boolean onLongPress(Key key, PointerTracker tracker) { int primaryCode = key.mCode; if (primaryCode == Keyboard.CODE_SETTINGS) { return invokeOnKey(Keyboard.CODE_SETTINGS_LONGPRESS); @@ -102,7 +102,7 @@ public class LatinKeyboardView extends KeyboardView { // Long pressing on 0 in phone number keypad gives you a '+'. return invokeOnKey('+'); } else { - return super.onLongPress(key); + return super.onLongPress(key, tracker); } } diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java new file mode 100644 index 000000000..3b1408ccf --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * 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; + +import android.content.Context; + +public class MiniKeyboard extends Keyboard { + private int mDefaultKeyCoordX; + + public MiniKeyboard(Context context, int xmlLayoutResId, KeyboardId id) { + super(context, xmlLayoutResId, id); + } + + public void setDefaultCoordX(int pos) { + mDefaultKeyCoordX = pos; + } + + public int getDefaultCoordX() { + return mDefaultKeyCoordX; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java index c150baadb..53dab9440 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java @@ -27,44 +27,141 @@ import java.util.List; public class MiniKeyboardBuilder { private final Resources mRes; - private final Keyboard mKeyboard; + private final MiniKeyboard mKeyboard; private final CharSequence[] mPopupCharacters; - private final int mMiniKeyboardKeyHorizontalPadding; - private final int mKeyWidth; - private final int mMaxColumns; - private final int mNumRows; - private int mColPos; - private int mRowPos; - private int mX; - private int mY; + private final MiniKeyboardLayoutParams mParams; + + /* package */ static class MiniKeyboardLayoutParams { + public final int mKeyWidth; + public final int mRowHeight; + /* package */ final boolean mTopRowNeedsCentering; + public final int mNumRows; + public final int mNumColumns; + public final int mLeftKeys; + public final int mRightKeys; // includes default key. + + /** + * The object holding mini keyboard layout parameters. + * + * @param numKeys number of keys in this mini keyboard. + * @param maxColumns number of maximum columns of this mini keyboard. + * @param keyWidth mini keyboard key width in pixel, including horizontal gap. + * @param rowHeight mini keyboard row height in pixel, including vertical gap. + * @param coordXInParent coordinate x of the popup key in parent keyboard. + * @param parentKeyboardWidth parent keyboard width in pixel. + */ + public MiniKeyboardLayoutParams(int numKeys, int maxColumns, int keyWidth, int rowHeight, + int coordXInParent, int parentKeyboardWidth) { + if (parentKeyboardWidth / keyWidth < maxColumns) + throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: " + + parentKeyboardWidth + " " + keyWidth + " " + maxColumns); + final int numRows = (numKeys + maxColumns - 1) / maxColumns; + mKeyWidth = keyWidth; + mRowHeight = rowHeight; + mNumRows = numRows; + + final int numColumns = Math.min(numKeys, maxColumns); + final int topRowKeys = numKeys % numColumns; + mNumColumns = numColumns; + mTopRowNeedsCentering = topRowKeys != 0 && (numColumns - topRowKeys) % 2 != 0; + + final int numLeftKeys = (numColumns - 1) / 2; + final int numRightKeys = numColumns - numLeftKeys; // including default key. + final int maxLeftKeys = coordXInParent / keyWidth; + final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth); + if (numLeftKeys > maxLeftKeys) { + mLeftKeys = maxLeftKeys; + mRightKeys = numColumns - maxLeftKeys; + } else if (numRightKeys > maxRightKeys) { + mLeftKeys = numColumns - maxRightKeys; + mRightKeys = maxRightKeys; + } else { + mLeftKeys = numLeftKeys; + mRightKeys = numRightKeys; + } + } + + // Return key position according to column count (0 is default). + /* package */ int getColumnPos(int n) { + final int col = n % mNumColumns; + if (col == 0) { + // default position. + return 0; + } + int pos = 0; + int right = 1; // include default position key. + int left = 0; + int i = 0; + while (true) { + // Assign right key if available. + if (right < mRightKeys) { + pos = right; + right++; + i++; + } + if (i >= col) + break; + // Assign left key if available. + if (left < mLeftKeys) { + left++; + pos = -left; + i++; + } + if (i >= col) + break; + } + return pos; + } + + public int getDefaultKeyCoordX() { + return mLeftKeys * mKeyWidth; + } + + public int getX(int n, int row) { + final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX(); + if (isLastRow(row) && mTopRowNeedsCentering) + return x - mKeyWidth / 2; + return x; + } + + public int getY(int row) { + return (mNumRows - 1 - row) * mRowHeight; + } + + public int getRowFlags(int row) { + int rowFlags = 0; + if (row == 0) rowFlags |= Keyboard.EDGE_TOP; + if (isLastRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM; + return rowFlags; + } + + private boolean isLastRow(int rowCount) { + return rowCount == mNumRows - 1; + } + } public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key popupKey) { final Context context = view.getContext(); mRes = context.getResources(); - final Keyboard keyboard = new Keyboard(context, layoutTemplateResId, null); + final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null); mKeyboard = keyboard; mPopupCharacters = popupKey.mPopupCharacters; - mMiniKeyboardKeyHorizontalPadding = (int)mRes.getDimension( - R.dimen.mini_keyboard_key_horizontal_padding); - mKeyWidth = getMaxKeyWidth(view, mPopupCharacters, mKeyboard.getKeyWidth()); - final int maxColumns = popupKey.mMaxPopupColumn; - mMaxColumns = maxColumns; - final int numKeys = mPopupCharacters.length; - int numRows = numKeys / maxColumns; - if (numKeys % maxColumns != 0) numRows++; - mNumRows = numRows; - keyboard.setHeight((keyboard.getRowHeight() + keyboard.getVerticalGap()) * numRows - - keyboard.getVerticalGap()); - if (numRows > 1) { - mColPos = numKeys % maxColumns; - if (mColPos > 0) mColPos = maxColumns - mColPos; - // Centering top-row keys. - mX = mColPos * (mKeyWidth + keyboard.getHorizontalGap()) / 2; - } - mKeyboard.setMinWidth(0); + + final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth()); + final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + mPopupCharacters.length, popupKey.mMaxPopupColumn, + keyWidth, keyboard.getRowHeight(), + popupKey.mX + (popupKey.mWidth + popupKey.mGap) / 2 - keyWidth / 2, + view.getMeasuredWidth()); + mParams = params; + + keyboard.setHeight(params.mNumRows * params.mRowHeight - keyboard.getVerticalGap()); + keyboard.setMinWidth(params.mNumColumns * params.mKeyWidth); + keyboard.setDefaultCoordX(params.getDefaultKeyCoordX() + params.mKeyWidth / 2); } - private int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters, int minKeyWidth) { + private static int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters, + int minKeyWidth) { Paint paint = null; Rect bounds = null; int maxWidth = 0; @@ -84,46 +181,22 @@ public class MiniKeyboardBuilder { maxWidth = bounds.width(); } } - return Math.max(minKeyWidth, maxWidth + mMiniKeyboardKeyHorizontalPadding); + final int horizontalPadding = (int)view.getContext().getResources().getDimension( + R.dimen.mini_keyboard_key_horizontal_padding); + return Math.max(minKeyWidth, maxWidth + horizontalPadding); } - public Keyboard build() { - final Keyboard keyboard = mKeyboard; + public MiniKeyboard build() { + final MiniKeyboard keyboard = mKeyboard; final List keys = keyboard.getKeys(); - for (CharSequence label : mPopupCharacters) { - refresh(); - final Key key = new Key(mRes, keyboard, label, mX, mY, mKeyWidth, getRowFlags()); + 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.getRowFlags(row)); keys.add(key); - advance(); } return keyboard; } - - private int getRowFlags() { - final int rowPos = mRowPos; - int rowFlags = 0; - if (rowPos == 0) rowFlags |= Keyboard.EDGE_TOP; - if (rowPos == mNumRows - 1) rowFlags |= Keyboard.EDGE_BOTTOM; - return rowFlags; - } - - private void refresh() { - if (mColPos >= mMaxColumns) { - final Keyboard keyboard = mKeyboard; - // TODO: Allocate key position depending the precedence of popup characters. - mX = 0; - mY += keyboard.getRowHeight() + keyboard.getVerticalGap(); - mColPos = 0; - mRowPos++; - } - } - - private void advance() { - final Keyboard keyboard = mKeyboard; - // TODO: Allocate key position depending the precedence of popup characters. - mX += mKeyWidth + keyboard.getHorizontalGap(); - if (mX > keyboard.getMinWidth()) - keyboard.setMinWidth(mX); - mColPos++; - } } diff --git a/tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java b/tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java new file mode 100644 index 000000000..7e3106d7f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java @@ -0,0 +1,312 @@ +/* + * 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; + +import com.android.inputmethod.keyboard.MiniKeyboardBuilder.MiniKeyboardLayoutParams; + +import android.test.AndroidTestCase; + +public class MiniKeyboardBuilderTests extends AndroidTestCase { + private static final int MAX_COLUMNS = 5; + private static final int WIDTH = 10; + private static final int HEIGHT = 10; + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + public void testLayoutError() { + MiniKeyboardLayoutParams params = null; + try { + params = new MiniKeyboardLayoutParams( + 10, MAX_COLUMNS + 1, WIDTH, HEIGHT, + WIDTH * 2, WIDTH * MAX_COLUMNS); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // Too small keyboard to hold mini keyboard. + } + assertNull("Too small keyboard to hold mini keyboard", params); + } + + // Mini keyboard layout test. + // "[n]" represents n-th key position in mini keyboard. + // "[1]" is the default key. + + // [1] + public void testLayout1Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 1, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("1 key columns", 1, params.mNumColumns); + assertEquals("1 key rows", 1, params.mNumRows); + assertEquals("1 key left", 0, params.mLeftKeys); + assertEquals("1 key right", 1, params.mRightKeys); + assertEquals("1 key [1]", 0, params.getColumnPos(0)); + assertEquals("1 key centering", false, params.mTopRowNeedsCentering); + assertEquals("1 key default", 0, params.getDefaultKeyCoordX()); + } + + // [1] [2] + public void testLayout2Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 2, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("2 key columns", 2, params.mNumColumns); + assertEquals("2 key rows", 1, params.mNumRows); + assertEquals("2 key left", 0, params.mLeftKeys); + assertEquals("2 key right", 2, params.mRightKeys); + assertEquals("2 key [1]", 0, params.getColumnPos(0)); + assertEquals("2 key [2]", 1, params.getColumnPos(1)); + assertEquals("2 key centering", false, params.mTopRowNeedsCentering); + assertEquals("2 key default", 0, params.getDefaultKeyCoordX()); + } + + // [3] [1] [2] + public void testLayout3Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 3, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("3 key columns", 3, params.mNumColumns); + assertEquals("3 key rows", 1, params.mNumRows); + assertEquals("3 key left", 1, params.mLeftKeys); + assertEquals("3 key right", 2, params.mRightKeys); + assertEquals("3 key [1]", 0, params.getColumnPos(0)); + assertEquals("3 key [2]", 1, params.getColumnPos(1)); + assertEquals("3 key [3]", -1, params.getColumnPos(2)); + assertEquals("3 key centering", false, params.mTopRowNeedsCentering); + assertEquals("3 key default", WIDTH, params.getDefaultKeyCoordX()); + } + + // [3] [1] [2] [4] + public void testLayout4Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 4, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("4 key columns", 4, params.mNumColumns); + assertEquals("4 key rows", 1, params.mNumRows); + assertEquals("4 key left", 1, params.mLeftKeys); + assertEquals("4 key right", 3, params.mRightKeys); + assertEquals("4 key [1]", 0, params.getColumnPos(0)); + assertEquals("4 key [2]", 1, params.getColumnPos(1)); + assertEquals("4 key [3]", -1, params.getColumnPos(2)); + assertEquals("4 key [4]", 2, params.getColumnPos(3)); + assertEquals("4 key centering", false, params.mTopRowNeedsCentering); + assertEquals("4 key default", WIDTH, params.getDefaultKeyCoordX()); + } + + // [5] [3] [1] [2] [4] + public void testLayout5Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 5, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("5 key columns", 5, params.mNumColumns); + assertEquals("5 key rows", 1, params.mNumRows); + assertEquals("5 key left", 2, params.mLeftKeys); + assertEquals("5 key right", 3, params.mRightKeys); + assertEquals("5 key [1]", 0, params.getColumnPos(0)); + assertEquals("5 key [2]", 1, params.getColumnPos(1)); + assertEquals("5 key [3]", -1, params.getColumnPos(2)); + assertEquals("5 key [4]", 2, params.getColumnPos(3)); + assertEquals("5 key [5]", -2, params.getColumnPos(4)); + assertEquals("5 key centering", false, params.mTopRowNeedsCentering); + assertEquals("5 key default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [6] + // [5] [3] [1] [2] [4] + public void testLayout6Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 6, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("6 key columns", 5, params.mNumColumns); + assertEquals("6 key rows", 2, params.mNumRows); + assertEquals("6 key left", 2, params.mLeftKeys); + assertEquals("6 key right", 3, params.mRightKeys); + assertEquals("6 key [1]", 0, params.getColumnPos(0)); + assertEquals("6 key [2]", 1, params.getColumnPos(1)); + assertEquals("6 key [3]", -1, params.getColumnPos(2)); + assertEquals("6 key [4]", 2, params.getColumnPos(3)); + assertEquals("6 key [5]", -2, params.getColumnPos(4)); + assertEquals("6 key [6]", 0, params.getColumnPos(5)); + assertEquals("6 key centering", false, params.mTopRowNeedsCentering); + assertEquals("6 key default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [6] [7] + // [5] [3] [1] [2] [4] + public void testLayout7Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 7, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("7 key columns", 5, params.mNumColumns); + assertEquals("7 key rows", 2, params.mNumRows); + assertEquals("7 key left", 2, params.mLeftKeys); + assertEquals("7 key right", 3, params.mRightKeys); + assertEquals("7 key [1]", 0, params.getColumnPos(0)); + assertEquals("7 key [2]", 1, params.getColumnPos(1)); + assertEquals("7 key [3]", -1, params.getColumnPos(2)); + assertEquals("7 key [4]", 2, params.getColumnPos(3)); + assertEquals("7 key [5]", -2, params.getColumnPos(4)); + assertEquals("7 key [6]", 0, params.getColumnPos(5)); + assertEquals("7 key [7]", 1, params.getColumnPos(6)); + assertEquals("7 key centering", true, params.mTopRowNeedsCentering); + assertEquals("7 key default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [8] [6] [7] + // [5] [3] [1] [2] [4] + public void testLayout8Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 8, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("8 key columns", 5, params.mNumColumns); + assertEquals("8 key rows", 2, params.mNumRows); + assertEquals("8 key left", 2, params.mLeftKeys); + assertEquals("8 key right", 3, params.mRightKeys); + assertEquals("8 key [1]", 0, params.getColumnPos(0)); + assertEquals("8 key [2]", 1, params.getColumnPos(1)); + assertEquals("8 key [3]", -1, params.getColumnPos(2)); + assertEquals("8 key [4]", 2, params.getColumnPos(3)); + assertEquals("8 key [5]", -2, params.getColumnPos(4)); + assertEquals("8 key [6]", 0, params.getColumnPos(5)); + assertEquals("8 key [7]", 1, params.getColumnPos(6)); + assertEquals("8 key [8]", -1, params.getColumnPos(7)); + assertEquals("8 key centering", false, params.mTopRowNeedsCentering); + assertEquals("8 key default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [8] [6] [7] [9] + // [5] [3] [1] [2] [4] + public void testLayout9Key() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 9, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 5, WIDTH * 10); + assertEquals("9 key columns", 5, params.mNumColumns); + assertEquals("9 key rows", 2, params.mNumRows); + assertEquals("9 key left", 2, params.mLeftKeys); + assertEquals("9 key right", 3, params.mRightKeys); + assertEquals("9 key [1]", 0, params.getColumnPos(0)); + assertEquals("9 key [2]", 1, params.getColumnPos(1)); + assertEquals("9 key [3]", -1, params.getColumnPos(2)); + assertEquals("9 key [4]", 2, params.getColumnPos(3)); + assertEquals("9 key [5]", -2, params.getColumnPos(4)); + assertEquals("9 key [6]", 0, params.getColumnPos(5)); + assertEquals("9 key [7]", 1, params.getColumnPos(6)); + assertEquals("9 key [8]", -1, params.getColumnPos(7)); + assertEquals("9 key [9]", 2, params.getColumnPos(8)); + assertEquals("9 key centering", true, params.mTopRowNeedsCentering); + assertEquals("9 key default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // Nine keys test. There is no key space for mini keyboard at left of the parent key. + // [6] [7] [8] [9] + // [1] [2] [3] [4] [5] + public void testLayout9KeyLeft() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 9, MAX_COLUMNS, WIDTH, HEIGHT, + 0, WIDTH * 10); + assertEquals("9 key left columns", 5, params.mNumColumns); + assertEquals("9 key left rows", 2, params.mNumRows); + assertEquals("9 key left left", 0, params.mLeftKeys); + assertEquals("9 key left right", 5, params.mRightKeys); + assertEquals("9 key left [1]", 0, params.getColumnPos(0)); + assertEquals("9 key left [2]", 1, params.getColumnPos(1)); + assertEquals("9 key left [3]", 2, params.getColumnPos(2)); + assertEquals("9 key left [4]", 3, params.getColumnPos(3)); + assertEquals("9 key left [5]", 4, params.getColumnPos(4)); + assertEquals("9 key left [6]", 0, params.getColumnPos(5)); + assertEquals("9 key left [7]", 1, params.getColumnPos(6)); + assertEquals("9 key left [8]", 2, params.getColumnPos(7)); + assertEquals("9 key left [9]", 3, params.getColumnPos(8)); + assertEquals("9 key left centering", true, params.mTopRowNeedsCentering); + assertEquals("9 key left default", 0, params.getDefaultKeyCoordX()); + } + + // Nine keys test. There is only one key space for mini keyboard at left of the parent key. + // [8] [6] [7] [9] + // [3] [1] [2] [4] [5] + public void testLayout9KeyNearLeft() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 9, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH, WIDTH * 10); + assertEquals("9 key near left columns", 5, params.mNumColumns); + assertEquals("9 key near left rows", 2, params.mNumRows); + assertEquals("9 key near left left", 1, params.mLeftKeys); + assertEquals("9 key near left right", 4, params.mRightKeys); + assertEquals("9 key near left [1]", 0, params.getColumnPos(0)); + assertEquals("9 key near left [2]", 1, params.getColumnPos(1)); + assertEquals("9 key near left [3]", -1, params.getColumnPos(2)); + assertEquals("9 key near left [4]", 2, params.getColumnPos(3)); + assertEquals("9 key near left [5]", 3, params.getColumnPos(4)); + assertEquals("9 key near left [6]", 0, params.getColumnPos(5)); + assertEquals("9 key near left [7]", 1, params.getColumnPos(6)); + assertEquals("9 key near left [8]", -1, params.getColumnPos(7)); + assertEquals("9 key near left [9]", 2, params.getColumnPos(8)); + assertEquals("9 key near left centering", true, params.mTopRowNeedsCentering); + assertEquals("9 key near left default", WIDTH, params.getDefaultKeyCoordX()); + } + + + // Nine keys test. There is no key space for mini keyboard at right of the parent key. + // [9] [8] [7] [6] + // [5] [4] [3] [2] [1] + public void testLayout9KeyRight() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 9, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 9, WIDTH * 10); + assertEquals("9 key right columns", 5, params.mNumColumns); + assertEquals("9 key right rows", 2, params.mNumRows); + assertEquals("9 key right left", 4, params.mLeftKeys); + assertEquals("9 key right right", 1, params.mRightKeys); + assertEquals("9 key right [1]", 0, params.getColumnPos(0)); + assertEquals("9 key right [2]", -1, params.getColumnPos(1)); + assertEquals("9 key right [3]", -2, params.getColumnPos(2)); + assertEquals("9 key right [4]", -3, params.getColumnPos(3)); + assertEquals("9 key right [5]", -4, params.getColumnPos(4)); + assertEquals("9 key right [6]", 0, params.getColumnPos(5)); + assertEquals("9 key right [7]", -1, params.getColumnPos(6)); + assertEquals("9 key right [8]", -2, params.getColumnPos(7)); + assertEquals("9 key right [9]", -3, params.getColumnPos(8)); + assertEquals("9 key right centering", true, params.mTopRowNeedsCentering); + assertEquals("9 key right default", WIDTH * 4, params.getDefaultKeyCoordX()); + } + + // Nine keys test. There is only one key space for mini keyboard at right of the parent key. + // [9] [8] [6] [7] + // [5] [4] [3] [1] [2] + public void testLayout9KeyNearRight() { + MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams( + 9, MAX_COLUMNS, WIDTH, HEIGHT, + WIDTH * 8, WIDTH * 10); + assertEquals("9 key near right columns", 5, params.mNumColumns); + assertEquals("9 key near right rows", 2, params.mNumRows); + assertEquals("9 key near right left", 3, params.mLeftKeys); + assertEquals("9 key near right right", 2, params.mRightKeys); + assertEquals("9 key near right [1]", 0, params.getColumnPos(0)); + assertEquals("9 key near right [2]", 1, params.getColumnPos(1)); + assertEquals("9 key near right [3]", -1, params.getColumnPos(2)); + assertEquals("9 key near right [4]", -2, params.getColumnPos(3)); + assertEquals("9 key near right [5]", -3, params.getColumnPos(4)); + assertEquals("9 key near right [6]", 0, params.getColumnPos(5)); + assertEquals("9 key near right [7]", 1, params.getColumnPos(6)); + assertEquals("9 key near right [8]", -1, params.getColumnPos(7)); + assertEquals("9 key near right [9]", -2, params.getColumnPos(8)); + assertEquals("9 key near right centering", true, params.mTopRowNeedsCentering); + assertEquals("9 key near right default", WIDTH * 3, params.getDefaultKeyCoordX()); + } +}