aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java')
-rw-r--r--java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java939
1 files changed, 349 insertions, 590 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
index 4007c2b55..c449b36e7 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
@@ -17,6 +17,7 @@
package com.android.inputmethod.latin;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -32,19 +33,20 @@ import android.inputmethodservice.Keyboard.Key;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
import android.widget.PopupWindow;
import android.widget.TextView;
+import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
+import java.util.LinkedList;
import java.util.Map;
/**
@@ -60,7 +62,11 @@ import java.util.Map;
* @attr ref R.styleable#LatinKeyboardBaseView_verticalCorrection
* @attr ref R.styleable#LatinKeyboardBaseView_popupLayout
*/
-public class LatinKeyboardBaseView extends View implements View.OnClickListener {
+public class LatinKeyboardBaseView extends View implements PointerTracker.UIProxy {
+ private static final String TAG = "LatinKeyboardBaseView";
+ private static final boolean DEBUG = false;
+
+ public static final int NOT_A_TOUCH_COORDINATE = -1;
public interface OnKeyboardActionListener {
@@ -139,116 +145,97 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
void swipeUp();
}
- public static final int NOT_A_TOUCH_COORDINATE = -1;
+ // Timing constants
+ private static final int DELAY_BEFORE_PREVIEW = 0;
+ private static final int DELAY_AFTER_PREVIEW = 70;
+ private static final int REPEAT_INTERVAL = PointerTracker.REPEAT_INTERVAL;
- private static final boolean DEBUG = false;
- static final int NOT_A_KEY = -1;
- private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE };
+ // Miscellaneous constants
+ /* package */ static final int NOT_A_KEY = -1;
private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable };
- private Keyboard mKeyboard;
- private int mCurrentKeyIndex = NOT_A_KEY;
- private int mLabelTextSize;
+ // XML attribute
private int mKeyTextSize;
private int mKeyTextColor;
- private float mShadowRadius;
+ private Typeface mKeyTextStyle = Typeface.DEFAULT;
+ private int mLabelTextSize;
+ private int mSymbolColorScheme = 0;
private int mShadowColor;
+ private float mShadowRadius;
+ private Drawable mKeyBackground;
private float mBackgroundDimAmount;
-
- private TextView mPreviewText;
- private PopupWindow mPreviewPopup;
- private int mPreviewTextSizeLarge;
+ private float mVerticalCorrection;
private int mPreviewOffset;
private int mPreviewHeight;
- private int[] mOffsetInWindow;
+ private int mPopupLayout;
- private PopupWindow mPopupKeyboard;
- private View mMiniKeyboardContainer;
- private LatinKeyboardBaseView mMiniKeyboard;
- private boolean mMiniKeyboardOnScreen;
- private View mPopupParent;
- private int mMiniKeyboardOffsetX;
- private int mMiniKeyboardOffsetY;
- private Map<Key,View> mMiniKeyboardCache;
- private int[] mWindowOffset;
+ // Main keyboard
+ private Keyboard mKeyboard;
private Key[] mKeys;
- private Typeface mKeyTextStyle = Typeface.DEFAULT;
- private int mSymbolColorScheme = 0;
- /** Listener for {@link OnKeyboardActionListener}. */
- private OnKeyboardActionListener mKeyboardActionListener;
-
- private static final int DELAY_BEFORE_PREVIEW = 0;
- private static final int DELAY_AFTER_PREVIEW = 70;
- private static final int DEBOUNCE_TIME = 70;
-
- private int mVerticalCorrection;
- private ProximityKeyDetector mProximityKeyDetector = new ProximityKeyDetector();
-
- private boolean mPreviewCentered = false;
+ // Key preview popup
+ private final static boolean PREVIEW_CENTERED = false;
+ private TextView mPreviewText;
+ private PopupWindow mPreviewPopup;
+ private int mPreviewTextSizeLarge;
+ private int[] mOffsetInWindow;
+ private int mOldPreviewKeyIndex = NOT_A_KEY;
private boolean mShowPreview = true;
private boolean mShowTouchPoints = true;
private int mPopupPreviewX;
private int mPopupPreviewY;
+ private int mPopupPreviewOffsetX;
+ private int mPopupPreviewOffsetY;
private int mWindowY;
- private Paint mPaint;
- private Rect mPadding;
-
- private int mCurrentKey = NOT_A_KEY;
- private int mStartX;
- private int mStartY;
-
- private KeyDebouncer mDebouncer;
-
- private GestureDetector mGestureDetector;
- private int mPopupX;
- private int mPopupY;
- private int mPopupLayout;
- private boolean mAbortKey;
- private Key mInvalidatedKey;
- private Rect mClipRegion = new Rect(0, 0, 0, 0);
- private SwipeTracker mSwipeTracker = new SwipeTracker();
- private int mSwipeThreshold;
- private boolean mDisambiguateSwipe;
+ // Popup mini keyboard
+ private PopupWindow mMiniKeyboardPopup;
+ private LatinKeyboardBaseView mMiniKeyboard;
+ private View mMiniKeyboardParent;
+ private Map<Key,View> mMiniKeyboardCache;
+ private int mMiniKeyboardOriginX;
+ private int mMiniKeyboardOriginY;
+ private long mMiniKeyboardPopupTime;
+ private int[] mWindowOffset;
- // Variables for dealing with multiple pointers
- private int mOldPointerCount = 1;
- private int mOldPointerX;
- private int mOldPointerY;
+ /** Listener for {@link OnKeyboardActionListener}. */
+ private OnKeyboardActionListener mKeyboardActionListener;
- private Drawable mKeyBackground;
+ private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>();
+ private final PointerQueue mPointerQueue = new PointerQueue();
+ private final float mDebounceHysteresis;
- private static final int REPEAT_INTERVAL = 50; // ~20 keys per second
- private static final int REPEAT_START_DELAY = 400;
- private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
+ protected KeyDetector mKeyDetector = new ProximityKeyDetector();
- // For multi-tap
- private int mLastSentIndex;
- private int mTapCount;
- private long mLastTapTime;
- private boolean mInMultiTap;
- private static final int MULTITAP_INTERVAL = 800; // milliseconds
- private StringBuilder mPreviewLabel = new StringBuilder(1);
+ // Swipe gesture detector
+ private final GestureDetector mGestureDetector;
+ private final SwipeTracker mSwipeTracker = new SwipeTracker();
+ private final int mSwipeThreshold;
+ private final boolean mDisambiguateSwipe;
+ // Drawing
/** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/
private boolean mDrawPending;
/** The dirty region in the keyboard bitmap */
- private Rect mDirtyRect = new Rect();
+ private final Rect mDirtyRect = new Rect();
/** The keyboard bitmap for faster updates */
private Bitmap mBuffer;
/** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */
private boolean mKeyboardChanged;
+ private Key mInvalidatedKey;
/** The canvas for the above mutable keyboard bitmap */
private Canvas mCanvas;
+ private final Paint mPaint;
+ private final Rect mPadding;
+ private final Rect mClipRegion = new Rect(0, 0, 0, 0);
- UIHandler mHandler = new UIHandler();
+ private final UIHandler mHandler = new UIHandler();
class UIHandler extends Handler {
private static final int MSG_POPUP_PREVIEW = 1;
private static final int MSG_DISMISS_PREVIEW = 2;
private static final int MSG_REPEAT_KEY = 3;
- private static final int MSG_LOGPRESS_KEY = 4;
+ private static final int MSG_LONGPRESS_KEY = 4;
private boolean mInKeyRepeat;
@@ -256,24 +243,34 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_POPUP_PREVIEW:
- showKey(msg.arg1);
+ showKey(msg.arg1, (PointerTracker)msg.obj);
break;
case MSG_DISMISS_PREVIEW:
mPreviewText.setVisibility(INVISIBLE);
break;
- case MSG_REPEAT_KEY:
- repeatKey(msg.arg1);
- startKeyRepeatTimer(REPEAT_INTERVAL, msg.arg1);
+ case MSG_REPEAT_KEY: {
+ final PointerTracker tracker = (PointerTracker)msg.obj;
+ tracker.repeatKey(msg.arg1);
+ startKeyRepeatTimer(REPEAT_INTERVAL, msg.arg1, tracker);
break;
- case MSG_LOGPRESS_KEY:
- openPopupIfRequired(msg.arg1);
+ }
+ case MSG_LONGPRESS_KEY: {
+ final PointerTracker tracker = (PointerTracker)msg.obj;
+ openPopupIfRequired(msg.arg1, tracker);
break;
+ }
}
}
- public void popupPreview(int keyIndex, long delay) {
+ public void popupPreview(long delay, int keyIndex, PointerTracker tracker) {
removeMessages(MSG_POPUP_PREVIEW);
- sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0), delay);
+ if (mPreviewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) {
+ // Show right away, if it's already visible and finger is moving around
+ showKey(keyIndex, tracker);
+ } else {
+ sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0, tracker),
+ delay);
+ }
}
public void cancelPopupPreview() {
@@ -281,16 +278,18 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
}
public void dismissPreview(long delay) {
- sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay);
+ if (mPreviewPopup.isShowing()) {
+ sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay);
+ }
}
public void cancelDismissPreview() {
removeMessages(MSG_DISMISS_PREVIEW);
}
- public void startKeyRepeatTimer(long delay, int keyIndex) {
+ public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {
mInKeyRepeat = true;
- sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0), delay);
+ sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0, tracker), delay);
}
public void cancelKeyRepeatTimer() {
@@ -302,13 +301,13 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
return mInKeyRepeat;
}
- public void startLongPressTimer(int keyIndex, long delay) {
- removeMessages(MSG_LOGPRESS_KEY);
- sendMessageDelayed(obtainMessage(MSG_LOGPRESS_KEY, keyIndex, 0), delay);
+ public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {
+ removeMessages(MSG_LONGPRESS_KEY);
+ sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay);
}
public void cancelLongPressTimer() {
- removeMessages(MSG_LOGPRESS_KEY);
+ removeMessages(MSG_LONGPRESS_KEY);
}
public void cancelKeyTimers() {
@@ -323,109 +322,38 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
}
};
- static class KeyDebouncer {
- private final Key[] mKeys;
- private final int mKeyDebounceThresholdSquared;
-
- // for move de-bouncing
- private int mLastCodeX;
- private int mLastCodeY;
- private int mLastX;
- private int mLastY;
-
- // for time de-bouncing
- private int mLastKey;
- private long mLastKeyTime;
- private long mLastMoveTime;
- private long mCurrentKeyTime;
-
- KeyDebouncer(Key[] keys, float hysteresisPixel) {
- if (keys == null || hysteresisPixel < 1.0f)
- throw new IllegalArgumentException();
- mKeys = keys;
- mKeyDebounceThresholdSquared = (int)(hysteresisPixel * hysteresisPixel);
- }
-
- public int getLastCodeX() {
- return mLastCodeX;
- }
-
- public int getLastCodeY() {
- return mLastCodeY;
- }
-
- public int getLastX() {
- return mLastX;
- }
-
- public int getLastY() {
- return mLastY;
- }
-
- public int getLastKey() {
- return mLastKey;
- }
-
- public void startMoveDebouncing(int x, int y) {
- mLastCodeX = x;
- mLastCodeY = y;
- }
+ static class PointerQueue {
+ private LinkedList<PointerTracker> mQueue = new LinkedList<PointerTracker>();
- public void updateMoveDebouncing(int x, int y) {
- mLastX = x;
- mLastY = y;
+ public void add(PointerTracker tracker) {
+ mQueue.add(tracker);
}
- public void resetMoveDebouncing() {
- mLastCodeX = mLastX;
- mLastCodeY = mLastY;
- }
-
- public boolean isMinorMoveBounce(int x, int y, int newKey, int curKey) {
- if (newKey == curKey) {
- return true;
- } else if (curKey >= 0 && curKey < mKeys.length) {
- return getSquareDistanceToKeyEdge(x, y, mKeys[curKey])
- < mKeyDebounceThresholdSquared;
- } else {
- return false;
+ public int lastIndexOf(PointerTracker tracker) {
+ LinkedList<PointerTracker> queue = mQueue;
+ for (int index = queue.size() - 1; index >= 0; index--) {
+ PointerTracker t = queue.get(index);
+ if (t == tracker)
+ return index;
}
+ return -1;
}
- private static int getSquareDistanceToKeyEdge(int x, int y, Key key) {
- final int left = key.x;
- final int right = key.x + key.width;
- final int top = key.y;
- final int bottom = key.y + key.height;
- final int edgeX = x < left ? left : (x > right ? right : x);
- final int edgeY = y < top ? top : (y > bottom ? bottom : y);
- final int dx = x - edgeX;
- final int dy = y - edgeY;
- return dx * dx + dy * dy;
- }
-
- public void startTimeDebouncing(long eventTime) {
- mLastKey = NOT_A_KEY;
- mLastKeyTime = 0;
- mCurrentKeyTime = 0;
- mLastMoveTime = eventTime;
- }
-
- public void updateTimeDebouncing(long eventTime) {
- mCurrentKeyTime += eventTime - mLastMoveTime;
- mLastMoveTime = eventTime;
- }
-
- public void resetTimeDebouncing(long eventTime, int currentKey) {
- mLastKey = currentKey;
- mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime;
- mCurrentKeyTime = 0;
- mLastMoveTime = eventTime;
+ public void releasePointersOlderThan(PointerTracker tracker, long eventTime) {
+ LinkedList<PointerTracker> queue = mQueue;
+ int oldestPos = 0;
+ for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) {
+ if (t.isModifier()) {
+ oldestPos++;
+ } else {
+ t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
+ queue.remove(oldestPos);
+ }
+ }
}
- public boolean isMinorTimeBounce() {
- return mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < DEBOUNCE_TIME
- && mLastKey != NOT_A_KEY;
+ public void remove(PointerTracker tracker) {
+ mQueue.remove(tracker);
}
}
@@ -516,15 +444,11 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
} else {
mShowPreview = false;
}
-
mPreviewPopup.setTouchable(false);
+ mMiniKeyboardParent = this;
- mPopupKeyboard = new PopupWindow(context);
- mPopupKeyboard.setBackgroundDrawable(null);
- //mPopupKeyboard.setClippingEnabled(false);
-
- mPopupParent = this;
- //mPredicting = true;
+ mMiniKeyboardPopup = new PopupWindow(context);
+ mMiniKeyboardPopup.setBackgroundDrawable(null);
mPaint = new Paint();
mPaint.setAntiAlias(true);
@@ -536,19 +460,17 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
mMiniKeyboardCache = new HashMap<Key,View>();
mKeyBackground.getPadding(mPadding);
- mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density);
+ final Resources res = getResources();
+ mSwipeThreshold = (int) (500 * res.getDisplayMetrics().density);
// TODO: Refer frameworks/base/core/res/res/values/config.xml
- mDisambiguateSwipe = getResources().getBoolean(R.bool.config_swipeDisambiguation);
- resetMultiTap();
- initGestureDetector();
- }
+ mDisambiguateSwipe = res.getBoolean(R.bool.config_swipeDisambiguation);
+ mDebounceHysteresis = res.getDimension(R.dimen.key_debounce_hysteresis_distance);
- private void initGestureDetector() {
GestureDetector.SimpleOnGestureListener listener =
new GestureDetector.SimpleOnGestureListener() {
@Override
- public boolean onFling(MotionEvent me1, MotionEvent me2,
- float velocityX, float velocityY) {
+ public boolean onFling(MotionEvent me1, MotionEvent me2, float velocityX,
+ float velocityY) {
final float absX = Math.abs(velocityX);
final float absY = Math.abs(velocityY);
float deltaX = me2.getX() - me1.getX();
@@ -590,6 +512,9 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
mKeyboardActionListener = listener;
+ for (PointerTracker tracker : mPointerTrackers) {
+ tracker.setOnKeyboardActionListener(listener);
+ }
}
/**
@@ -609,26 +534,24 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
*/
public void setKeyboard(Keyboard keyboard) {
if (mKeyboard != null) {
- showPreview(NOT_A_KEY);
+ dismissKeyPreview();
}
// Remove any pending messages, except dismissing preview
mHandler.cancelKeyTimers();
mHandler.cancelPopupPreview();
mKeyboard = keyboard;
- LatinImeLogger.onSetKeyboard(mKeyboard);
- List<Key> keys = mKeyboard.getKeys();
- mKeys = keys.toArray(new Key[keys.size()]);
- mProximityKeyDetector.setKeyboard(keyboard, mKeys);
+ LatinImeLogger.onSetKeyboard(keyboard);
+ mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
+ -getPaddingTop() + mVerticalCorrection);
+ for (PointerTracker tracker : mPointerTrackers) {
+ tracker.setKeyboard(mKeys, mDebounceHysteresis);
+ }
requestLayout();
// Hint to reallocate the buffer if the size changed
mKeyboardChanged = true;
invalidateAllKeys();
computeProximityThreshold(keyboard);
mMiniKeyboardCache.clear();
- // Not really necessary to do every time, but will free up views
- // Switching to a different keyboard should abort any pending keys so that the key up
- // doesn't get delivered to the old or new keyboard
- mAbortKey = true; // Until the next ACTION_DOWN
}
/**
@@ -691,16 +614,13 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
return mSymbolColorScheme;
}
- public void setVerticalCorrection(int verticalOffset) {
- }
-
public void setPopupParent(View v) {
- mPopupParent = v;
+ mMiniKeyboardParent = v;
}
public void setPopupOffset(int x, int y) {
- mMiniKeyboardOffsetX = x;
- mMiniKeyboardOffsetY = y;
+ mPopupPreviewOffsetX = x;
+ mPopupPreviewOffsetY = y;
if (mPreviewPopup.isShowing()) {
mPreviewPopup.dismiss();
}
@@ -713,22 +633,14 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
* @param enabled whether or not the proximity correction is enabled
*/
public void setProximityCorrectionEnabled(boolean enabled) {
- mProximityKeyDetector.setProximityCorrectionEnabled(enabled);
+ mKeyDetector.setProximityCorrectionEnabled(enabled);
}
/**
* Returns true if proximity correction is enabled.
*/
public boolean isProximityCorrectionEnabled() {
- return mProximityKeyDetector.isProximityCorrectionEnabled();
- }
-
- /**
- * Popup keyboard close button clicked.
- * @hide
- */
- public void onClick(View v) {
- dismissPopupKeyboard();
+ return mKeyDetector.isProximityCorrectionEnabled();
}
protected CharSequence adjustCase(CharSequence label) {
@@ -772,11 +684,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
dimensionSum += Math.min(key.width, key.height) + key.gap;
}
if (dimensionSum < 0 || length == 0) return;
- mProximityKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length));
-
- final float hysteresisPixel = getContext().getResources()
- .getDimension(R.dimen.key_debounce_hysteresis_distance);
- mDebouncer = new KeyDebouncer(keys, hysteresisPixel);
+ mKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length));
}
@Override
@@ -889,23 +797,27 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
}
mInvalidatedKey = null;
// Overlay a dark rectangle to dim the keyboard
- if (mMiniKeyboardOnScreen) {
+ if (mMiniKeyboard != null) {
paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24);
canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
}
if (DEBUG) {
if (mShowTouchPoints) {
- int lastX = mDebouncer.getLastX();
- int lastY = mDebouncer.getLastY();
- paint.setAlpha(128);
- paint.setColor(0xFFFF0000);
- canvas.drawCircle(mStartX, mStartY, 3, paint);
- canvas.drawLine(mStartX, mStartY, lastX, lastY, paint);
- paint.setColor(0xFF0000FF);
- canvas.drawCircle(lastX, lastY, 3, paint);
- paint.setColor(0xFF00FF00);
- canvas.drawCircle((mStartX + lastX) / 2, (mStartY + lastY) / 2, 2, paint);
+ for (PointerTracker tracker : mPointerTrackers) {
+ int startX = tracker.getStartX();
+ int startY = tracker.getStartY();
+ int lastX = tracker.getLastX();
+ int lastY = tracker.getLastY();
+ paint.setAlpha(128);
+ paint.setColor(0xFFFF0000);
+ canvas.drawCircle(startX, startY, 3, paint);
+ canvas.drawLine(startX, startY, lastX, lastY, paint);
+ paint.setColor(0xFF0000FF);
+ canvas.drawCircle(lastX, lastY, 3, paint);
+ paint.setColor(0xFF00FF00);
+ canvas.drawCircle((startX + lastX) / 2, (startY + lastY) / 2, 2, paint);
+ }
}
}
@@ -913,105 +825,39 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
mDirtyRect.setEmpty();
}
-
- private void detectAndSendKey(int index, int x, int y, long eventTime) {
- if (index != NOT_A_KEY && index < mKeys.length) {
- final Key key = mKeys[index];
- if (key.text != null) {
- mKeyboardActionListener.onText(key.text);
- mKeyboardActionListener.onRelease(NOT_A_KEY);
- } else {
- int code = key.codes[0];
- //TextEntryState.keyPressedAt(key, x, y);
- int[] codes = mProximityKeyDetector.newCodeArray();
- mProximityKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes);
- // Multi-tap
- if (mInMultiTap) {
- if (mTapCount != -1) {
- mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE, x, y);
- } else {
- mTapCount = 0;
- }
- code = key.codes[mTapCount];
- }
- /*
- * Swap the first and second values in the codes array if the primary code is not
- * the first value but the second value in the array. This happens when key
- * debouncing is in effect.
- */
- if (codes.length >= 2 && codes[0] != code && codes[1] == code) {
- codes[1] = codes[0];
- codes[0] = code;
- }
- mKeyboardActionListener.onKey(code, codes, x, y);
- mKeyboardActionListener.onRelease(code);
- }
- mLastSentIndex = index;
- mLastTapTime = eventTime;
- }
+ // TODO: clean up this method.
+ private void dismissKeyPreview() {
+ for (PointerTracker tracker : mPointerTrackers)
+ tracker.updateKey(NOT_A_KEY);
+ showPreview(NOT_A_KEY, null);
}
- /**
- * Handle multi-tap keys by producing the key label for the current multi-tap state.
- */
- private CharSequence getPreviewText(Key key) {
- if (mInMultiTap) {
- // Multi-tap
- mPreviewLabel.setLength(0);
- mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]);
- return adjustCase(mPreviewLabel);
- } else {
- return adjustCase(key.label);
- }
- }
-
- private void showPreview(int keyIndex) {
- int oldKeyIndex = mCurrentKeyIndex;
- final PopupWindow previewPopup = mPreviewPopup;
-
- mCurrentKeyIndex = keyIndex;
- // Release the old key and press the new key
- final Key[] keys = mKeys;
- if (oldKeyIndex != mCurrentKeyIndex) {
- if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) {
- keys[oldKeyIndex].onReleased(mCurrentKeyIndex == NOT_A_KEY);
- invalidateKey(oldKeyIndex);
- }
- if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) {
- keys[mCurrentKeyIndex].onPressed();
- invalidateKey(mCurrentKeyIndex);
- }
- }
+ public void showPreview(int keyIndex, PointerTracker tracker) {
+ int oldKeyIndex = mOldPreviewKeyIndex;
+ mOldPreviewKeyIndex = keyIndex;
// If key changed and preview is on ...
- if (oldKeyIndex != mCurrentKeyIndex && mShowPreview) {
+ if (oldKeyIndex != keyIndex && mShowPreview) {
if (keyIndex == NOT_A_KEY) {
mHandler.cancelPopupPreview();
- if (previewPopup.isShowing()) {
- mHandler.dismissPreview(DELAY_AFTER_PREVIEW);
- }
- } else {
- if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) {
- // Show right away, if it's already visible and finger is moving around
- showKey(keyIndex);
- } else {
- mHandler.popupPreview(keyIndex, DELAY_BEFORE_PREVIEW);
- }
+ mHandler.dismissPreview(DELAY_AFTER_PREVIEW);
+ } else if (tracker != null) {
+ mHandler.popupPreview(DELAY_BEFORE_PREVIEW, keyIndex, tracker);
}
}
}
- private void showKey(final int keyIndex) {
+ private void showKey(final int keyIndex, PointerTracker tracker) {
+ Key key = tracker.getKey(keyIndex);
+ if (key == null)
+ return;
final PopupWindow previewPopup = mPreviewPopup;
- final Key[] keys = mKeys;
- if (keyIndex < 0 || keyIndex >= mKeys.length) return;
- Key key = keys[keyIndex];
if (key.icon != null) {
mPreviewText.setCompoundDrawables(null, null, null,
key.iconPreview != null ? key.iconPreview : key.icon);
mPreviewText.setText(null);
} else {
mPreviewText.setCompoundDrawables(null, null, null, null);
- mPreviewText.setText(getPreviewText(key));
+ mPreviewText.setText(adjustCase(tracker.getPreviewText(key)));
if (key.label.length() > 1 && key.codes.length < 2) {
mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize);
mPreviewText.setTypeface(Typeface.DEFAULT_BOLD);
@@ -1030,20 +876,20 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
lp.width = popupWidth;
lp.height = popupHeight;
}
- if (!mPreviewCentered) {
- mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + getPaddingLeft();
- mPopupPreviewY = key.y - popupHeight + mPreviewOffset;
- } else {
+ if (PREVIEW_CENTERED) {
// TODO: Fix this if centering is brought back
mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2;
mPopupPreviewY = - mPreviewText.getMeasuredHeight();
+ } else {
+ mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + getPaddingLeft();
+ mPopupPreviewY = key.y - popupHeight + mPreviewOffset;
}
mHandler.cancelDismissPreview();
if (mOffsetInWindow == null) {
mOffsetInWindow = new int[2];
getLocationInWindow(mOffsetInWindow);
- mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero
- mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero
+ mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero
+ mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero
int[] mWindowLocation = new int[2];
getLocationOnScreen(mWindowLocation);
mWindowY = mWindowLocation[1];
@@ -1072,7 +918,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
} else {
previewPopup.setWidth(popupWidth);
previewPopup.setHeight(popupHeight);
- previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY,
+ previewPopup.showAtLocation(mMiniKeyboardParent, Gravity.NO_GRAVITY,
mPopupPreviewX, mPopupPreviewY);
}
mPreviewText.setVisibility(VISIBLE);
@@ -1082,7 +928,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
* Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient
* because the keyboard renders the keys to an off-screen buffer and an invalidate() only
* draws the cached buffer.
- * @see #invalidateKey(int)
+ * @see #invalidateKey(Key)
*/
public void invalidateAllKeys() {
mDirtyRect.union(0, 0, getWidth(), getHeight());
@@ -1094,15 +940,12 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
* Invalidates a key so that it will be redrawn on the next repaint. Use this method if only
* one key is changing it's content. Any changes that affect the position or size of the key
* may not be honored.
- * @param keyIndex the index of the key in the attached {@link Keyboard}.
+ * @param key key in the attached {@link Keyboard}.
* @see #invalidateAllKeys
*/
- public void invalidateKey(int keyIndex) {
- if (mKeys == null) return;
- if (keyIndex < 0 || keyIndex >= mKeys.length) {
+ public void invalidateKey(Key key) {
+ if (key == null)
return;
- }
- final Key key = mKeys[keyIndex];
mInvalidatedKey = key;
mDirtyRect.union(key.x + getPaddingLeft(), key.y + getPaddingTop(),
key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop());
@@ -1111,24 +954,75 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop());
}
- private boolean openPopupIfRequired(int keyIndex) {
+ private boolean openPopupIfRequired(int keyIndex, PointerTracker tracker) {
// Check if we have a popup layout specified first.
if (mPopupLayout == 0) {
return false;
}
- if (keyIndex < 0 || keyIndex >= mKeys.length) {
- return false;
- }
- Key popupKey = mKeys[keyIndex];
+ Key popupKey = tracker.getKey(keyIndex);
+ if (popupKey == null)
+ return false;
boolean result = onLongPress(popupKey);
if (result) {
- mAbortKey = true;
- showPreview(NOT_A_KEY);
+ dismissKeyPreview();
+ tracker.setAlreadyProcessed();
}
return result;
}
+ private View inflateMiniKeyboardContainer(Key popupKey) {
+ int popupKeyboardId = popupKey.popupResId;
+ LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View container = inflater.inflate(mPopupLayout, null);
+ if (container == null)
+ throw new NullPointerException();
+
+ mMiniKeyboard = (LatinKeyboardBaseView)container.findViewById(R.id.LatinKeyboardBaseView);
+ mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() {
+ public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
+ mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y);
+ dismissPopupKeyboard();
+ }
+
+ public void onText(CharSequence text) {
+ mKeyboardActionListener.onText(text);
+ dismissPopupKeyboard();
+ }
+
+ public void swipeLeft() {
+ }
+ public void swipeRight() {
+ }
+ public void swipeUp() {
+ }
+ public void swipeDown() {
+ }
+ public void onPress(int primaryCode) {
+ mKeyboardActionListener.onPress(primaryCode);
+ }
+ public void onRelease(int primaryCode) {
+ mKeyboardActionListener.onRelease(primaryCode);
+ }
+ });
+
+ Keyboard keyboard;
+ if (popupKey.popupCharacters != null) {
+ keyboard = new Keyboard(getContext(), popupKeyboardId, popupKey.popupCharacters,
+ -1, getPaddingLeft() + getPaddingRight());
+ } else {
+ keyboard = new Keyboard(getContext(), popupKeyboardId);
+ }
+ mMiniKeyboard.setKeyboard(keyboard);
+ mMiniKeyboard.setPopupParent(this);
+
+ container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
+
+ return container;
+ }
+
/**
* Called when a key is long pressed. By default this will open any popup keyboard associated
* with this key through the attributes popupLayout and popupCharacters.
@@ -1137,123 +1031,99 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
* method on the base class if the subclass doesn't wish to handle the call.
*/
protected boolean onLongPress(Key popupKey) {
- int popupKeyboardId = popupKey.popupResId;
+ // TODO if popupKey.popupCharacters has only one letter, send it as key without opening
+ // mini keyboard.
- if (popupKeyboardId != 0) {
- mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey);
- if (mMiniKeyboardContainer == null) {
- LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null);
- mMiniKeyboard = (LatinKeyboardBaseView) mMiniKeyboardContainer.findViewById(
- R.id.LatinKeyboardBaseView);
- View closeButton = mMiniKeyboardContainer.findViewById(
- R.id.closeButton);
- if (closeButton != null) closeButton.setOnClickListener(this);
- mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() {
- public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
- mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y);
- dismissPopupKeyboard();
- }
+ if (popupKey.popupResId == 0)
+ return false;
- public void onText(CharSequence text) {
- mKeyboardActionListener.onText(text);
- dismissPopupKeyboard();
- }
+ View container = mMiniKeyboardCache.get(popupKey);
+ if (container == null) {
+ container = inflateMiniKeyboardContainer(popupKey);
+ mMiniKeyboardCache.put(popupKey, container);
+ }
+ mMiniKeyboard = (LatinKeyboardBaseView)container.findViewById(R.id.LatinKeyboardBaseView);
+ if (mWindowOffset == null) {
+ mWindowOffset = new int[2];
+ getLocationInWindow(mWindowOffset);
+ }
+ int popupX = popupKey.x + popupKey.width + getPaddingLeft();
+ int popupY = popupKey.y + getPaddingTop();
+ popupX -= container.getMeasuredWidth();
+ popupY -= container.getMeasuredHeight();
+ popupX += mWindowOffset[0];
+ popupY += mWindowOffset[1];
+ final int x = popupX + container.getPaddingRight();
+ final int y = popupY + container.getPaddingBottom();
+ mMiniKeyboardOriginX = (x < 0 ? 0 : x) + container.getPaddingLeft();
+ mMiniKeyboardOriginY = y + container.getPaddingTop();
+ mMiniKeyboard.setPopupOffset((x < 0) ? 0 : x, y);
+ mMiniKeyboard.setShifted(isShifted());
+ mMiniKeyboard.setPreviewEnabled(isPreviewEnabled());
+ 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 = System.currentTimeMillis();
+ mMiniKeyboardPopupTime = eventTime;
+ MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, popupKey.x
+ + popupKey.width / 2, popupKey.y + popupKey.height / 2, eventTime);
+ mMiniKeyboard.onTouchEvent(downEvent);
+ downEvent.recycle();
- public void swipeLeft() { }
- public void swipeRight() { }
- public void swipeUp() { }
- public void swipeDown() { }
- public void onPress(int primaryCode) {
- mKeyboardActionListener.onPress(primaryCode);
- }
- public void onRelease(int primaryCode) {
- mKeyboardActionListener.onRelease(primaryCode);
- }
- });
- //mInputView.setSuggest(mSuggest);
- Keyboard keyboard;
- if (popupKey.popupCharacters != null) {
- keyboard = new Keyboard(getContext(), popupKeyboardId,
- popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight());
- } else {
- keyboard = new Keyboard(getContext(), popupKeyboardId);
- }
- mMiniKeyboard.setKeyboard(keyboard);
- mMiniKeyboard.setPopupParent(this);
- mMiniKeyboardContainer.measure(
- MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
-
- mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer);
- } else {
- mMiniKeyboard = (LatinKeyboardBaseView) mMiniKeyboardContainer.findViewById(
- R.id.LatinKeyboardBaseView);
- }
- if (mWindowOffset == null) {
- mWindowOffset = new int[2];
- getLocationInWindow(mWindowOffset);
- }
- mPopupX = popupKey.x + getPaddingLeft();
- mPopupY = popupKey.y + getPaddingTop();
- mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth();
- mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight();
- final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mWindowOffset[0];
- final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mWindowOffset[1];
- mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y);
- mMiniKeyboard.setShifted(isShifted());
- mPopupKeyboard.setContentView(mMiniKeyboardContainer);
- mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth());
- mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight());
- mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
- mMiniKeyboardOnScreen = true;
- //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me));
- invalidateAllKeys();
- return true;
- }
- return false;
+ invalidateAllKeys();
+ return true;
}
- private int getTouchX(float x) {
- return (int)x - getPaddingLeft();
+ private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) {
+ return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action,
+ x - mMiniKeyboardOriginX, y - mMiniKeyboardOriginY, 0);
}
- private int getTouchY(float y) {
- return (int)y + mVerticalCorrection - getPaddingTop();
+ private PointerTracker getPointerTracker(final int id) {
+ final ArrayList<PointerTracker> pointers = mPointerTrackers;
+ final Key[] keys = mKeys;
+ final OnKeyboardActionListener listener = mKeyboardActionListener;
+
+ // 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, mHandler, mKeyDetector, this);
+ if (keys != null)
+ tracker.setKeyboard(keys, mDebounceHysteresis);
+ if (listener != null)
+ tracker.setOnKeyboardActionListener(listener);
+ pointers.add(tracker);
+ }
+
+ return pointers.get(id);
}
@Override
public boolean onTouchEvent(MotionEvent me) {
- // Convert multi-pointer up/down events to single up/down events to
- // deal with the typical multi-pointer behavior of two-thumb typing
final int pointerCount = me.getPointerCount();
- final int action = me.getAction();
+ final int action = me.getActionMasked();
final long eventTime = me.getEventTime();
- if (pointerCount > 1 && mOldPointerCount > 1) {
- // Don't do anything when 2 or more pointers are down and moving.
- return true;
- }
-
// Track the last few movements to look for spurious swipes.
mSwipeTracker.addMovement(me);
- // Ignore all motion events until a DOWN.
- if (mAbortKey
- && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) {
- return true;
- }
-
- if (mGestureDetector.onTouchEvent(me)) {
- showPreview(NOT_A_KEY);
+ // We must disable gesture detector while mini-keyboard is on the screen.
+ if (mMiniKeyboard == null && mGestureDetector.onTouchEvent(me)) {
+ dismissKeyPreview();
mHandler.cancelKeyTimers();
return true;
}
// Needs to be called after the gesture detector gets a turn, as it may have
// displayed the mini keyboard
- if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) {
+ if (mMiniKeyboard != null) {
+ MotionEvent translated = generateMiniKeyboardMotionEvent(action, (int)me.getX(),
+ (int)me.getY(), eventTime);
+ mMiniKeyboard.onTouchEvent(translated);
+ translated.recycle();
return true;
}
@@ -1268,145 +1138,58 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
// Up event will pass through.
}
- int touchX = getTouchX(me.getX());
- int touchY = getTouchY(me.getY());
- if (pointerCount != mOldPointerCount) {
- if (pointerCount == 1) {
- // Send a down event for the latest pointer
- onDownEvent(touchX, touchY, eventTime);
- // If it's an up action, then deliver the up as well.
- if (action == MotionEvent.ACTION_UP) {
- onUpEvent(touchX, touchY, eventTime);
- }
- } else {
- // Send an up event for the last pointer
- onUpEvent(mOldPointerX, mOldPointerY, eventTime);
+ if (action == MotionEvent.ACTION_MOVE) {
+ for (int index = 0; index < pointerCount; index++) {
+ int x = (int)me.getX(index);
+ int y = (int)me.getY(index);
+ int id = me.getPointerId(index);
+ PointerTracker tracker = getPointerTracker(id);
+ tracker.onMoveEvent(x, y, eventTime);
}
- mOldPointerCount = pointerCount;
- return true;
} else {
- if (pointerCount == 1) {
- onModifiedTouchEvent(action, touchX, touchY, eventTime);
- mOldPointerX = touchX;
- mOldPointerY = touchY;
- return true;
- }
- }
-
- return false;
- }
-
- private void onModifiedTouchEvent(int action, int touchX, int touchY, long eventTime) {
- switch (action) {
+ int index = me.getActionIndex();
+ int x = (int)me.getX(index);
+ int y = (int)me.getY(index);
+ int id = me.getPointerId(index);
+ PointerTracker tracker = getPointerTracker(id);
+ switch (action) {
case MotionEvent.ACTION_DOWN:
- onDownEvent(touchX, touchY, eventTime);
- break;
- case MotionEvent.ACTION_MOVE:
- onMoveEvent(touchX, touchY, eventTime);
+ case MotionEvent.ACTION_POINTER_DOWN:
+ onDownEvent(tracker, x, y, eventTime);
break;
case MotionEvent.ACTION_UP:
- onUpEvent(touchX, touchY, eventTime);
+ case MotionEvent.ACTION_POINTER_UP:
+ onUpEvent(tracker, x, y, eventTime);
break;
case MotionEvent.ACTION_CANCEL:
- onCancelEvent(touchX, touchY, eventTime);
+ onCancelEvent(tracker, x, y, eventTime);
break;
- }
- }
-
- private void onDownEvent(int touchX, int touchY, long eventTime) {
- int keyIndex = mProximityKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null);
- mAbortKey = false;
- mCurrentKey = keyIndex;
- mStartX = touchX;
- mStartY = touchY;
- mDebouncer.startMoveDebouncing(touchX, touchY);
- mDebouncer.startTimeDebouncing(eventTime);
- checkMultiTap(eventTime, keyIndex);
- mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ? mKeys[keyIndex].codes[0] : 0);
- if (keyIndex >= 0 && mKeys[keyIndex].repeatable) {
- repeatKey(keyIndex);
- mHandler.startKeyRepeatTimer(REPEAT_START_DELAY, keyIndex);
- // Delivering the key could have caused an abort
- if (mAbortKey) {
- mHandler.cancelKeyRepeatTimer();
- return;
}
}
- if (keyIndex != NOT_A_KEY) {
- mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT);
- }
- showPreview(keyIndex);
- mDebouncer.updateMoveDebouncing(touchX, touchY);
+
+ return true;
}
- private void onMoveEvent(int touchX, int touchY, long eventTime) {
- int keyIndex = mProximityKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null);
- if (keyIndex != NOT_A_KEY) {
- if (mCurrentKey == NOT_A_KEY) {
- mDebouncer.updateTimeDebouncing(eventTime);
- mCurrentKey = keyIndex;
- mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT);
- } else if (mDebouncer.isMinorMoveBounce(touchX, touchY, keyIndex, mCurrentKey)) {
- mDebouncer.updateTimeDebouncing(eventTime);
- } else {
- resetMultiTap();
- mDebouncer.resetTimeDebouncing(eventTime, mCurrentKey);
- mDebouncer.resetMoveDebouncing();
- mCurrentKey = keyIndex;
- mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT);
- }
- } else {
- mHandler.cancelLongPressTimer();
- }
- /*
- * While time debouncing is in effect, mCurrentKey holds the new key and mDebouncer
- * holds the last key. At ACTION_UP event if time debouncing will be in effect
- * eventually, the last key should be sent as the result. In such case mCurrentKey
- * should not be showed as popup preview.
- */
- showPreview(mDebouncer.isMinorTimeBounce() ? mDebouncer.getLastKey() : mCurrentKey);
- mDebouncer.updateMoveDebouncing(touchX, touchY);
+ private void onDownEvent(PointerTracker tracker, int x, int y, long eventTime) {
+ tracker.onDownEvent(x, y, eventTime);
+ mPointerQueue.add(tracker);
}
- private void onUpEvent(int touchX, int touchY, long eventTime) {
- int keyIndex = mProximityKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null);
- boolean wasInKeyRepeat = mHandler.isInKeyRepeat();
- mHandler.cancelKeyTimers();
- mHandler.cancelPopupPreview();
- if (mDebouncer.isMinorMoveBounce(touchX, touchY, keyIndex, mCurrentKey)) {
- mDebouncer.updateTimeDebouncing(eventTime);
+ private void onUpEvent(PointerTracker tracker, int x, int y, long eventTime) {
+ int index = mPointerQueue.lastIndexOf(tracker);
+ if (index >= 0) {
+ mPointerQueue.releasePointersOlderThan(tracker, eventTime);
} else {
- resetMultiTap();
- mDebouncer.resetTimeDebouncing(eventTime, mCurrentKey);
- mCurrentKey = keyIndex;
- }
- if (mDebouncer.isMinorTimeBounce()) {
- mCurrentKey = mDebouncer.getLastKey();
- touchX = mDebouncer.getLastCodeX();
- touchY = mDebouncer.getLastCodeY();
- }
- showPreview(NOT_A_KEY);
- // If we're not on a repeating key (which sends on a DOWN event)
- if (!wasInKeyRepeat && !mMiniKeyboardOnScreen && !mAbortKey) {
- detectAndSendKey(mCurrentKey, touchX, touchY, eventTime);
+ Log.w(TAG, "onUpEvent: corresponding down event not found for pointer "
+ + tracker.mPointerId);
}
- invalidateKey(keyIndex);
+ tracker.onUpEvent(x, y, eventTime);
+ mPointerQueue.remove(tracker);
}
- private void onCancelEvent(int touchX, int touchY, long eventTime) {
- mHandler.cancelKeyTimers();
- mHandler.cancelPopupPreview();
- dismissPopupKeyboard();
- mAbortKey = true;
- showPreview(NOT_A_KEY);
- invalidateKey(mCurrentKey);
- }
-
- private void repeatKey(int keyIndex) {
- Key key = mKeys[keyIndex];
- // While key is repeating, because there is no need to handle multi-tap key, we can pass
- // -1 as eventTime argument.
- detectAndSendKey(keyIndex, key.x, key.y, -1);
+ private void onCancelEvent(PointerTracker tracker, int x, int y, long eventTime) {
+ tracker.onCancelEvent(x, y, eventTime);
+ mPointerQueue.remove(tracker);
}
protected void swipeRight() {
@@ -1444,44 +1227,20 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener
}
private void dismissPopupKeyboard() {
- if (mPopupKeyboard.isShowing()) {
- mPopupKeyboard.dismiss();
- mMiniKeyboardOnScreen = false;
+ if (mMiniKeyboardPopup.isShowing()) {
+ mMiniKeyboardPopup.dismiss();
+ mMiniKeyboard = null;
+ mMiniKeyboardOriginX = 0;
+ mMiniKeyboardOriginY = 0;
invalidateAllKeys();
}
}
public boolean handleBack() {
- if (mPopupKeyboard.isShowing()) {
+ if (mMiniKeyboardPopup.isShowing()) {
dismissPopupKeyboard();
return true;
}
return false;
}
-
- private void resetMultiTap() {
- mLastSentIndex = NOT_A_KEY;
- mTapCount = 0;
- mLastTapTime = -1;
- mInMultiTap = false;
- }
-
- private void checkMultiTap(long eventTime, int keyIndex) {
- if (keyIndex == NOT_A_KEY) return;
- Key key = mKeys[keyIndex];
- if (key.codes.length > 1) {
- mInMultiTap = true;
- if (eventTime < mLastTapTime + MULTITAP_INTERVAL
- && keyIndex == mLastSentIndex) {
- mTapCount = (mTapCount + 1) % key.codes.length;
- return;
- } else {
- mTapCount = -1;
- return;
- }
- }
- if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) {
- resetMultiTap();
- }
- }
}