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
This commit is contained in:
Tadashi G. Takaoka 2011-07-10 18:09:15 -07:00
parent 08eea95650
commit 63c233ab9f
5 changed files with 147 additions and 84 deletions

View file

@ -21,6 +21,7 @@ import android.content.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Message; import android.os.Message;
import android.os.SystemClock;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.view.GestureDetector; import android.view.GestureDetector;
@ -65,7 +66,8 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
// Mini keyboard // Mini keyboard
private PopupWindow mPopupWindow; private PopupWindow mPopupWindow;
private PopupPanel mPopupMiniKeyboardPanel; private PopupPanel mPopupPanel;
private int mPopupPanelPointerTrackerId;
private final WeakHashMap<Key, PopupPanel> mPopupPanelCache = private final WeakHashMap<Key, PopupPanel> mPopupPanelCache =
new WeakHashMap<Key, PopupPanel>(); new WeakHashMap<Key, PopupPanel>();
@ -363,15 +365,13 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
return false; return false;
} }
// Check if we are already displaying popup panel.
if (mPopupPanel != null)
return false;
final Key parentKey = tracker.getKey(keyIndex); final Key parentKey = tracker.getKey(keyIndex);
if (parentKey == null) if (parentKey == null)
return false; return false;
boolean result = onLongPress(parentKey, tracker); return onLongPress(parentKey, tracker);
if (result) {
dismissAllKeyPreviews();
tracker.onLongPressed();
}
return result;
} }
private void onLongPressShiftKey(PointerTracker tracker) { private void onLongPressShiftKey(PointerTracker tracker) {
@ -398,35 +398,6 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
final PopupMiniKeyboardView miniKeyboardView = final PopupMiniKeyboardView miniKeyboardView =
(PopupMiniKeyboardView)container.findViewById(R.id.mini_keyboard_view); (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 parentKeyboard = getKeyboard();
final Keyboard miniKeyboard = new MiniKeyboardBuilder( final Keyboard miniKeyboard = new MiniKeyboardBuilder(
this, parentKeyboard.getPopupKeyboardResId(), parentKey, parentKeyboard).build(); this, parentKeyboard.getPopupKeyboardResId(), parentKey, parentKeyboard).build();
@ -440,7 +411,7 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
@Override @Override
protected boolean needsToDimKeyboard() { 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. // Allow popup window to be drawn off the screen.
mPopupWindow.setClippingEnabled(false); mPopupWindow.setClippingEnabled(false);
} }
mPopupMiniKeyboardPanel = popupPanel; mPopupPanel = popupPanel;
mPopupPanelPointerTrackerId = tracker.mPointerId;
tracker.onLongPressed();
popupPanel.showPanel(this, parentKey, tracker, mPopupWindow); 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(); invalidateAllKeys();
return true; return true;
@ -476,15 +453,12 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
private PointerTracker getPointerTracker(final int id) { private PointerTracker getPointerTracker(final int id) {
final ArrayList<PointerTracker> pointers = mPointerTrackers; final ArrayList<PointerTracker> pointers = mPointerTrackers;
final KeyboardActionListener listener = mKeyboardActionListener; final KeyboardActionListener listener = mKeyboardActionListener;
final Keyboard keyboard = getKeyboard();
// Create pointer trackers until we can get 'id+1'-th tracker, if needed. // Create pointer trackers until we can get 'id+1'-th tracker, if needed.
for (int i = pointers.size(); i <= id; i++) { for (int i = pointers.size(); i <= id; i++) {
final PointerTracker tracker = final PointerTracker tracker =
new PointerTracker(i, getContext(), mKeyTimerHandler, mKeyDetector, this, new PointerTracker(i, getContext(), mKeyTimerHandler, mKeyDetector, this,
mPointerQueue); mPointerQueue);
if (keyboard != null)
tracker.setKeyDetector(mKeyDetector);
if (listener != null) if (listener != null)
tracker.setKeyboardActionListener(listener); tracker.setKeyboardActionListener(listener);
pointers.add(tracker); pointers.add(tracker);
@ -494,10 +468,12 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
} }
public boolean isInSlidingKeyInput() { public boolean isInSlidingKeyInput() {
if (mPopupMiniKeyboardPanel != null) { if (mPopupPanel != null) {
return mPopupMiniKeyboardPanel.isInSlidingKeyInput(); return true;
} else { } else if (mPointerQueue != null) {
return mPointerQueue.isInSlidingKeyInput(); 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. // 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)) { && mGestureDetector.onTouchEvent(me)) {
dismissAllKeyPreviews(); dismissAllKeyPreviews();
mKeyTimerHandler.cancelKeyTimers(); mKeyTimerHandler.cancelKeyTimers();
@ -531,13 +507,13 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
final long eventTime = me.getEventTime(); final long eventTime = me.getEventTime();
final int index = me.getActionIndex(); final int index = me.getActionIndex();
final int id = me.getPointerId(index); final int id = me.getPointerId(index);
final int x = (int)me.getX(index); final int x, y;
final int y = (int)me.getY(index); if (mPopupPanel != null && id == mPopupPanelPointerTrackerId) {
x = mPopupPanel.translateX((int)me.getX(index));
// Needs to be called after the gesture detector gets a turn, as it may have displayed the y = mPopupPanel.translateY((int)me.getY(index));
// mini keyboard } else {
if (mPopupMiniKeyboardPanel != null) { x = (int)me.getX(index);
return mPopupMiniKeyboardPanel.onTouchEvent(me); y = (int)me.getY(index);
} }
if (mKeyTimerHandler.isInKeyRepeat()) { if (mKeyTimerHandler.isInKeyRepeat()) {
@ -585,7 +561,15 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
if (action == MotionEvent.ACTION_MOVE) { if (action == MotionEvent.ACTION_MOVE) {
for (int i = 0; i < pointerCount; i++) { for (int i = 0; i < pointerCount; i++) {
final PointerTracker tracker = getPointerTracker(me.getPointerId(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 { } else {
processMotionEvent(getPointerTracker(id), action, x, y, eventTime, this); processMotionEvent(getPointerTracker(id), action, x, y, eventTime, this);
@ -618,10 +602,11 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
mPopupPanelCache.clear(); mPopupPanelCache.clear();
} }
private boolean dismissMiniKeyboard() { public boolean dismissMiniKeyboard() {
if (mPopupWindow != null && mPopupWindow.isShowing()) { if (mPopupWindow != null && mPopupWindow.isShowing()) {
mPopupWindow.dismiss(); mPopupWindow.dismiss();
mPopupMiniKeyboardPanel = null; mPopupPanel = null;
mPopupPanelPointerTrackerId = -1;
invalidateAllKeys(); invalidateAllKeys();
return true; return true;
} }

View file

@ -96,8 +96,10 @@ public class LatinKeyboardView extends LatinKeyboardBaseView {
protected boolean onLongPress(Key key, PointerTracker tracker) { protected boolean onLongPress(Key key, PointerTracker tracker) {
int primaryCode = key.mCode; int primaryCode = key.mCode;
if (primaryCode == Keyboard.CODE_SETTINGS) { if (primaryCode == Keyboard.CODE_SETTINGS) {
tracker.onLongPressed();
return invokeOnKey(Keyboard.CODE_SETTINGS_LONGPRESS); return invokeOnKey(Keyboard.CODE_SETTINGS_LONGPRESS);
} else if (primaryCode == '0' && getLatinKeyboard().isPhoneKeyboard()) { } else if (primaryCode == '0' && getLatinKeyboard().isPhoneKeyboard()) {
tracker.onLongPressed();
// Long pressing on 0 in phone number keypad gives you a '+'. // Long pressing on 0 in phone number keypad gives you a '+'.
return invokeOnKey('+'); return invokeOnKey('+');
} else { } else {

View file

@ -18,7 +18,6 @@ package com.android.inputmethod.keyboard;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.SystemClock;
import android.util.Log; import android.util.Log;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
@ -361,6 +360,7 @@ public class PointerTracker {
printTouchEvent("onDownEvent:", x, y, eventTime); printTouchEvent("onDownEvent:", x, y, eventTime);
mDrawingProxy = handler.getDrawingProxy(); mDrawingProxy = handler.getDrawingProxy();
mTimerProxy = handler.getTimerProxy();
setKeyboardActionListener(handler.getKeyboardActionListener()); setKeyboardActionListener(handler.getKeyboardActionListener());
setKeyDetectorInner(handler.getKeyDetector()); setKeyDetectorInner(handler.getKeyDetector());
// Naive up-to-down noise filter. // Naive up-to-down noise filter.
@ -598,10 +598,10 @@ public class PointerTracker {
public void onLongPressed() { public void onLongPressed() {
mKeyAlreadyProcessed = true; mKeyAlreadyProcessed = true;
setReleasedKeyGraphics();
dismissKeyPreview();
final PointerTrackerQueue queue = mPointerTrackerQueue; final PointerTrackerQueue queue = mPointerTrackerQueue;
if (queue != null) { if (queue != null) {
// TODO: Support chording + long-press input.
queue.releaseAllPointersExcept(this, SystemClock.uptimeMillis(), true);
queue.remove(this); queue.remove(this);
} }
} }

View file

@ -18,26 +18,73 @@ package com.android.inputmethod.keyboard;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.SystemClock; import android.content.res.TypedArray;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
/** /**
* A view that renders a virtual {@link MiniKeyboard}. It handles rendering of keys and detecting * A view that renders a virtual {@link MiniKeyboard}. It handles rendering of keys and detecting
* key presses and touch movements. * 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 int[] mCoordinates = new int[2];
private final boolean mConfigShowMiniKeyboardAtTouchedPoint; private final boolean mConfigShowMiniKeyboardAtTouchedPoint;
private final KeyDetector mKeyDetector;
private final int mVerticalCorrection;
private LatinKeyboardBaseView mParentKeyboardView;
private int mOriginX; private int mOriginX;
private int mOriginY; 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) { public PopupMiniKeyboardView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.popupMiniKeyboardViewStyle); 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) { public PopupMiniKeyboardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, 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(); final Resources res = context.getResources();
mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean( mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean(
R.bool.config_show_mini_keyboard_at_touched_point); 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( mKeyDetector = new MiniKeyboardKeyDetector(res.getDimension(
R.dimen.mini_keyboard_slide_allowance)); R.dimen.mini_keyboard_slide_allowance));
// Remove gesture detector on mini-keyboard // Remove gesture detector on mini-keyboard
mGestureDetector = null;
setKeyPreviewPopupEnabled(false, 0); 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 @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) { protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// Do nothing for the mini keyboard. // Do nothing for the mini keyboard.
@ -70,8 +149,9 @@ public class PopupMiniKeyboardView extends LatinKeyboardBaseView implements Popu
} }
@Override @Override
public void showPanel(KeyboardView parentKeyboardView, Key parentKey, public void showPanel(LatinKeyboardBaseView parentKeyboardView, Key parentKey,
PointerTracker tracker, PopupWindow window) { PointerTracker tracker, PopupWindow window) {
mParentKeyboardView = parentKeyboardView;
final View container = (View)getParent(); final View container = (View)getParent();
final MiniKeyboard miniKeyboard = (MiniKeyboard)getKeyboard(); final MiniKeyboard miniKeyboard = (MiniKeyboard)getKeyboard();
final Keyboard parentKeyboard = parentKeyboardView.getKeyboard(); final Keyboard parentKeyboard = parentKeyboardView.getKeyboard();
@ -99,19 +179,15 @@ public class PopupMiniKeyboardView extends LatinKeyboardBaseView implements Popu
mOriginX = x + container.getPaddingLeft() - mCoordinates[0]; mOriginX = x + container.getPaddingLeft() - mCoordinates[0];
mOriginY = y + container.getPaddingTop() - mCoordinates[1]; 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 @Override
public boolean onTouchEvent(MotionEvent me) { public int translateX(int x) {
me.offsetLocation(-mOriginX, -mOriginY); return x - mOriginX;
return super.onTouchEvent(me); }
@Override
public int translateY(int y) {
return y - mOriginY;
} }
} }

View file

@ -16,7 +16,6 @@
package com.android.inputmethod.keyboard; package com.android.inputmethod.keyboard;
import android.view.MotionEvent;
import android.widget.PopupWindow; import android.widget.PopupWindow;
public interface PopupPanel extends PointerTracker.KeyEventHandler { 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 tracker the pointer tracker that pressesd the parent key
* @param window PopupWindow to be used to show this popup panel * @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); PointerTracker tracker, PopupWindow window);
/** /**
* Check if the pointer is in siding key input mode. * Translate X-coordinate of touch event to the local X-coordinate of this PopupPanel.
* @return true if the pointer is sliding key input mode. * @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. * Translate Y-coordinate of touch event to the local Y-coordinate of this PopupPanel.
* @param me the MotionEvent to be processed. * @param y the global Y-coordinate
* @return true if the motion event is processed and should be consumed. * @return the local Y-coordinate to this PopupPanel
*/ */
public boolean onTouchEvent(MotionEvent me); public int translateY(int y);
} }