From 63c233ab9f50d844be6e52e382c6664475606760 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Sun, 10 Jul 2011 18:09:15 -0700 Subject: [PATCH] Fix mini keyboard behavior while chording input This change makes PopupMiniKeyboardView based on KeyboardView, so that only LatinKeyboardBaseView can manage touch event and PointerTracker. Bug: 4768084 Change-Id: Id30b132f1fae45da6e79ce822745cf0a653b8eb3 --- .../keyboard/LatinKeyboardBaseView.java | 95 +++++++-------- .../keyboard/LatinKeyboardView.java | 2 + .../inputmethod/keyboard/PointerTracker.java | 6 +- .../keyboard/PopupMiniKeyboardView.java | 110 +++++++++++++++--- .../inputmethod/keyboard/PopupPanel.java | 18 +-- 5 files changed, 147 insertions(+), 84 deletions(-) diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java index c4e37ff87..ea78fba99 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java @@ -21,6 +21,7 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Message; +import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; @@ -65,7 +66,8 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke // Mini keyboard private PopupWindow mPopupWindow; - private PopupPanel mPopupMiniKeyboardPanel; + private PopupPanel mPopupPanel; + private int mPopupPanelPointerTrackerId; private final WeakHashMap mPopupPanelCache = new WeakHashMap(); @@ -363,15 +365,13 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke return false; } + // Check if we are already displaying popup panel. + if (mPopupPanel != null) + return false; final Key parentKey = tracker.getKey(keyIndex); if (parentKey == null) return false; - boolean result = onLongPress(parentKey, tracker); - if (result) { - dismissAllKeyPreviews(); - tracker.onLongPressed(); - } - return result; + return onLongPress(parentKey, tracker); } private void onLongPressShiftKey(PointerTracker tracker) { @@ -398,35 +398,6 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke final PopupMiniKeyboardView miniKeyboardView = (PopupMiniKeyboardView)container.findViewById(R.id.mini_keyboard_view); - miniKeyboardView.setKeyboardActionListener(new KeyboardActionListener() { - @Override - public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { - mKeyboardActionListener.onCodeInput(primaryCode, keyCodes, x, y); - dismissMiniKeyboard(); - } - - @Override - public void onTextInput(CharSequence text) { - mKeyboardActionListener.onTextInput(text); - dismissMiniKeyboard(); - } - - @Override - public void onCancelInput() { - mKeyboardActionListener.onCancelInput(); - dismissMiniKeyboard(); - } - - @Override - public void onPress(int primaryCode, boolean withSliding) { - mKeyboardActionListener.onPress(primaryCode, withSliding); - } - @Override - public void onRelease(int primaryCode, boolean withSliding) { - mKeyboardActionListener.onRelease(primaryCode, withSliding); - } - }); - final Keyboard parentKeyboard = getKeyboard(); final Keyboard miniKeyboard = new MiniKeyboardBuilder( this, parentKeyboard.getPopupKeyboardResId(), parentKey, parentKeyboard).build(); @@ -440,7 +411,7 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke @Override protected boolean needsToDimKeyboard() { - return mPopupMiniKeyboardPanel != null; + return mPopupPanel != null; } /** @@ -466,8 +437,14 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke // Allow popup window to be drawn off the screen. mPopupWindow.setClippingEnabled(false); } - mPopupMiniKeyboardPanel = popupPanel; + mPopupPanel = popupPanel; + mPopupPanelPointerTrackerId = tracker.mPointerId; + + tracker.onLongPressed(); popupPanel.showPanel(this, parentKey, tracker, mPopupWindow); + final int translatedX = popupPanel.translateX(tracker.getLastX()); + final int translatedY = popupPanel.translateY(tracker.getLastY()); + tracker.onDownEvent(translatedX, translatedY, SystemClock.uptimeMillis(), popupPanel); invalidateAllKeys(); return true; @@ -476,15 +453,12 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke private PointerTracker getPointerTracker(final int id) { final ArrayList pointers = mPointerTrackers; final KeyboardActionListener listener = mKeyboardActionListener; - final Keyboard keyboard = getKeyboard(); // Create pointer trackers until we can get 'id+1'-th tracker, if needed. for (int i = pointers.size(); i <= id; i++) { final PointerTracker tracker = new PointerTracker(i, getContext(), mKeyTimerHandler, mKeyDetector, this, mPointerQueue); - if (keyboard != null) - tracker.setKeyDetector(mKeyDetector); if (listener != null) tracker.setKeyboardActionListener(listener); pointers.add(tracker); @@ -494,10 +468,12 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke } public boolean isInSlidingKeyInput() { - if (mPopupMiniKeyboardPanel != null) { - return mPopupMiniKeyboardPanel.isInSlidingKeyInput(); - } else { + if (mPopupPanel != null) { + return true; + } else if (mPointerQueue != null) { return mPointerQueue.isInSlidingKeyInput(); + } else { + return getPointerTracker(0).isInSlidingKeyInput(); } } @@ -521,7 +497,7 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke } // Gesture detector must be enabled only when mini-keyboard is not on the screen. - if (mPopupMiniKeyboardPanel == null && mGestureDetector != null + if (mPopupPanel == null && mGestureDetector != null && mGestureDetector.onTouchEvent(me)) { dismissAllKeyPreviews(); mKeyTimerHandler.cancelKeyTimers(); @@ -531,13 +507,13 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke final long eventTime = me.getEventTime(); final int index = me.getActionIndex(); final int id = me.getPointerId(index); - final int x = (int)me.getX(index); - final int y = (int)me.getY(index); - - // Needs to be called after the gesture detector gets a turn, as it may have displayed the - // mini keyboard - if (mPopupMiniKeyboardPanel != null) { - return mPopupMiniKeyboardPanel.onTouchEvent(me); + final int x, y; + if (mPopupPanel != null && id == mPopupPanelPointerTrackerId) { + x = mPopupPanel.translateX((int)me.getX(index)); + y = mPopupPanel.translateY((int)me.getY(index)); + } else { + x = (int)me.getX(index); + y = (int)me.getY(index); } if (mKeyTimerHandler.isInKeyRepeat()) { @@ -585,7 +561,15 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke if (action == MotionEvent.ACTION_MOVE) { for (int i = 0; i < pointerCount; i++) { final PointerTracker tracker = getPointerTracker(me.getPointerId(i)); - tracker.onMoveEvent((int)me.getX(i), (int)me.getY(i), eventTime); + final int px, py; + if (mPopupPanel != null && tracker.mPointerId == mPopupPanelPointerTrackerId) { + px = mPopupPanel.translateX((int)me.getX(i)); + py = mPopupPanel.translateY((int)me.getY(i)); + } else { + px = (int)me.getX(i); + py = (int)me.getY(i); + } + tracker.onMoveEvent(px, py, eventTime); } } else { processMotionEvent(getPointerTracker(id), action, x, y, eventTime, this); @@ -618,10 +602,11 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke mPopupPanelCache.clear(); } - private boolean dismissMiniKeyboard() { + public boolean dismissMiniKeyboard() { if (mPopupWindow != null && mPopupWindow.isShowing()) { mPopupWindow.dismiss(); - mPopupMiniKeyboardPanel = null; + mPopupPanel = null; + mPopupPanelPointerTrackerId = -1; invalidateAllKeys(); return true; } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 39d607d95..5f5475ce8 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -96,8 +96,10 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { protected boolean onLongPress(Key key, PointerTracker tracker) { int primaryCode = key.mCode; if (primaryCode == Keyboard.CODE_SETTINGS) { + tracker.onLongPressed(); return invokeOnKey(Keyboard.CODE_SETTINGS_LONGPRESS); } else if (primaryCode == '0' && getLatinKeyboard().isPhoneKeyboard()) { + tracker.onLongPressed(); // Long pressing on 0 in phone number keypad gives you a '+'. return invokeOnKey('+'); } else { diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 29a575ad0..d23fb4aad 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -18,7 +18,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.res.Resources; -import android.os.SystemClock; import android.util.Log; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; @@ -361,6 +360,7 @@ public class PointerTracker { printTouchEvent("onDownEvent:", x, y, eventTime); mDrawingProxy = handler.getDrawingProxy(); + mTimerProxy = handler.getTimerProxy(); setKeyboardActionListener(handler.getKeyboardActionListener()); setKeyDetectorInner(handler.getKeyDetector()); // Naive up-to-down noise filter. @@ -598,10 +598,10 @@ public class PointerTracker { public void onLongPressed() { mKeyAlreadyProcessed = true; + setReleasedKeyGraphics(); + dismissKeyPreview(); final PointerTrackerQueue queue = mPointerTrackerQueue; if (queue != null) { - // TODO: Support chording + long-press input. - queue.releaseAllPointersExcept(this, SystemClock.uptimeMillis(), true); queue.remove(this); } } diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java index a3d9c0465..af8e59568 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java @@ -18,26 +18,73 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.res.Resources; -import android.os.SystemClock; +import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.Gravity; -import android.view.MotionEvent; import android.view.View; import android.widget.PopupWindow; +import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; +import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.latin.R; /** * A view that renders a virtual {@link MiniKeyboard}. It handles rendering of keys and detecting * key presses and touch movements. */ -public class PopupMiniKeyboardView extends LatinKeyboardBaseView implements PopupPanel { +public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { private final int[] mCoordinates = new int[2]; private final boolean mConfigShowMiniKeyboardAtTouchedPoint; + private final KeyDetector mKeyDetector; + private final int mVerticalCorrection; + + private LatinKeyboardBaseView mParentKeyboardView; private int mOriginX; private int mOriginY; - private long mDownTime; + + private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy() { + @Override + public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {} + @Override + public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {} + @Override + public void startLongPressShiftTimer(long delay, int keyIndex, PointerTracker tracker) {} + @Override + public void cancelLongPressTimers() {} + @Override + public void cancelKeyTimers() {} + }; + + private final KeyboardActionListener mListner = new KeyboardActionListener() { + @Override + public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { + mParentKeyboardView.getKeyboardActionListener() + .onCodeInput(primaryCode, keyCodes, x, y); + mParentKeyboardView.dismissMiniKeyboard(); + } + + @Override + public void onTextInput(CharSequence text) { + mParentKeyboardView.getKeyboardActionListener().onTextInput(text); + mParentKeyboardView.dismissMiniKeyboard(); + } + + @Override + public void onCancelInput() { + mParentKeyboardView.getKeyboardActionListener().onCancelInput(); + mParentKeyboardView.dismissMiniKeyboard(); + } + + @Override + public void onPress(int primaryCode, boolean withSliding) { + mParentKeyboardView.getKeyboardActionListener().onPress(primaryCode, withSliding); + } + @Override + public void onRelease(int primaryCode, boolean withSliding) { + mParentKeyboardView.getKeyboardActionListener().onRelease(primaryCode, withSliding); + } + }; public PopupMiniKeyboardView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.popupMiniKeyboardViewStyle); @@ -46,6 +93,12 @@ public class PopupMiniKeyboardView extends LatinKeyboardBaseView implements Popu public PopupMiniKeyboardView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); + mVerticalCorrection = a.getDimensionPixelOffset( + R.styleable.KeyboardView_verticalCorrection, 0); + a.recycle(); + final Resources res = context.getResources(); mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean( R.bool.config_show_mini_keyboard_at_touched_point); @@ -53,10 +106,36 @@ public class PopupMiniKeyboardView extends LatinKeyboardBaseView implements Popu mKeyDetector = new MiniKeyboardKeyDetector(res.getDimension( R.dimen.mini_keyboard_slide_allowance)); // Remove gesture detector on mini-keyboard - mGestureDetector = null; setKeyPreviewPopupEnabled(false, 0); } + @Override + public void setKeyboard(Keyboard keyboard) { + super.setKeyboard(keyboard); + mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), + -getPaddingTop() + mVerticalCorrection); + } + + @Override + public KeyDetector getKeyDetector() { + return mKeyDetector; + } + + @Override + public KeyboardActionListener getKeyboardActionListener() { + return mListner; + } + + @Override + public DrawingProxy getDrawingProxy() { + return this; + } + + @Override + public TimerProxy getTimerProxy() { + return EMPTY_TIMER_PROXY; + } + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // Do nothing for the mini keyboard. @@ -70,8 +149,9 @@ public class PopupMiniKeyboardView extends LatinKeyboardBaseView implements Popu } @Override - public void showPanel(KeyboardView parentKeyboardView, Key parentKey, + public void showPanel(LatinKeyboardBaseView parentKeyboardView, Key parentKey, PointerTracker tracker, PopupWindow window) { + mParentKeyboardView = parentKeyboardView; final View container = (View)getParent(); final MiniKeyboard miniKeyboard = (MiniKeyboard)getKeyboard(); final Keyboard parentKeyboard = parentKeyboardView.getKeyboard(); @@ -99,19 +179,15 @@ public class PopupMiniKeyboardView extends LatinKeyboardBaseView implements Popu mOriginX = x + container.getPaddingLeft() - mCoordinates[0]; mOriginY = y + container.getPaddingTop() - mCoordinates[1]; - mDownTime = SystemClock.uptimeMillis(); - - // Inject down event on the key to mini keyboard. - final MotionEvent downEvent = MotionEvent.obtain(mDownTime, mDownTime, - MotionEvent.ACTION_DOWN, pointX - mOriginX, - pointY + parentKey.mHeight / 2 - mOriginY, 0); - onTouchEvent(downEvent); - downEvent.recycle(); } @Override - public boolean onTouchEvent(MotionEvent me) { - me.offsetLocation(-mOriginX, -mOriginY); - return super.onTouchEvent(me); + public int translateX(int x) { + return x - mOriginX; + } + + @Override + public int translateY(int y) { + return y - mOriginY; } } diff --git a/java/src/com/android/inputmethod/keyboard/PopupPanel.java b/java/src/com/android/inputmethod/keyboard/PopupPanel.java index 2d9130fcb..f94d1c562 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupPanel.java +++ b/java/src/com/android/inputmethod/keyboard/PopupPanel.java @@ -16,7 +16,6 @@ package com.android.inputmethod.keyboard; -import android.view.MotionEvent; import android.widget.PopupWindow; public interface PopupPanel extends PointerTracker.KeyEventHandler { @@ -27,19 +26,20 @@ public interface PopupPanel extends PointerTracker.KeyEventHandler { * @param tracker the pointer tracker that pressesd the parent key * @param window PopupWindow to be used to show this popup panel */ - public void showPanel(KeyboardView parentKeyboardView, Key parentKey, + public void showPanel(LatinKeyboardBaseView parentKeyboardView, Key parentKey, PointerTracker tracker, PopupWindow window); /** - * Check if the pointer is in siding key input mode. - * @return true if the pointer is sliding key input mode. + * Translate X-coordinate of touch event to the local X-coordinate of this PopupPanel. + * @param x the global X-coordinate + * @return the local X-coordinate to this PopupPanel */ - public boolean isInSlidingKeyInput(); + public int translateX(int x); /** - * The motion event handler. - * @param me the MotionEvent to be processed. - * @return true if the motion event is processed and should be consumed. + * Translate Y-coordinate of touch event to the local Y-coordinate of this PopupPanel. + * @param y the global Y-coordinate + * @return the local Y-coordinate to this PopupPanel */ - public boolean onTouchEvent(MotionEvent me); + public int translateY(int y); }