diff options
Diffstat (limited to 'java/src')
21 files changed, 622 insertions, 797 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index a87ff9891..8ca834148 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -29,7 +29,7 @@ import com.android.inputmethod.compat.AccessibilityEventCompatUtils; import com.android.inputmethod.compat.MotionEventCompatUtils; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; -import com.android.inputmethod.keyboard.KeyboardView; +import com.android.inputmethod.keyboard.LatinKeyboardBaseView; import com.android.inputmethod.keyboard.PointerTracker; public class AccessibleKeyboardViewProxy { @@ -40,7 +40,7 @@ public class AccessibleKeyboardViewProxy { private static final long DELAY_KEY_PRESS = 10; private int mScaledEdgeSlop; - private KeyboardView mView; + private LatinKeyboardBaseView mView; private AccessibleKeyboardActionListener mListener; private FlickGestureDetector mGestureDetector; @@ -57,7 +57,7 @@ public class AccessibleKeyboardViewProxy { return sInstance; } - public static void setView(KeyboardView view) { + public static void setView(LatinKeyboardBaseView view) { sInstance.mView = view; } @@ -200,8 +200,8 @@ public class AccessibleKeyboardViewProxy { } private void fireKeyPressEvent(PointerTracker tracker, int x, int y, long eventTime) { - tracker.onDownEvent(x, y, eventTime, null); - tracker.onUpEvent(x, y, eventTime + DELAY_KEY_PRESS, null); + tracker.onDownEvent(x, y, eventTime, mView); + tracker.onUpEvent(x, y, eventTime + DELAY_KEY_PRESS); } private class KeyboardFlickGestureDetector extends FlickGestureDetector { diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 85418a61d..6d25025c5 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -73,11 +73,10 @@ public class KeyDetector { return y + mCorrectionY; } - protected List<Key> getKeys() { + public Keyboard getKeyboard() { if (mKeyboard == null) throw new IllegalStateException("keyboard isn't set"); - // mKeyboard is guaranteed not to be null at setKeybaord() method if mKeys is not null - return mKeyboard.getKeys(); + return mKeyboard; } public void setProximityCorrectionEnabled(boolean enabled) { @@ -154,7 +153,7 @@ public class KeyDetector { } private void getNearbyKeyCodes(final int[] allCodes) { - final List<Key> keys = getKeys(); + final List<Key> keys = getKeyboard().getKeys(); final int[] indices = mIndices; // allCodes[0] should always have the key code even if it is a non-letter key. @@ -188,7 +187,7 @@ public class KeyDetector { * @return The nearest key index */ public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { - final List<Key> keys = getKeys(); + final List<Key> keys = getKeyboard().getKeys(); final int touchX = getTouchX(x); final int touchY = getTouchY(y); diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 280c0c9d8..0b4fce417 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -141,14 +141,6 @@ public class Keyboard { // TODO: Change GRID_WIDTH and GRID_HEIGHT to private. public final int GRID_WIDTH; public final int GRID_HEIGHT; - private final int GRID_SIZE; - private int mCellWidth; - private int mCellHeight; - private int[][] mGridNeighbors; - private int mProximityThreshold; - private static int[] EMPTY_INT_ARRAY = new int[0]; - /** Number of key widths from current touch point to search for nearest keys. */ - private static float SEARCH_DISTANCE = 1.2f; private final ProximityInfo mProximityInfo; @@ -164,7 +156,6 @@ public class Keyboard { final Resources res = context.getResources(); GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); - GRID_SIZE = GRID_WIDTH * GRID_HEIGHT; final int horizontalEdgesPadding = (int)res.getDimension( R.dimen.keyboard_horizontal_edges_padding); @@ -177,12 +168,13 @@ public class Keyboard { mDefaultVerticalGap = 0; mDefaultHeight = mDefaultWidth; mId = id; - mProximityInfo = new ProximityInfo(GRID_WIDTH, GRID_HEIGHT); loadKeyboard(context, xmlLayoutResId); + mProximityInfo = new ProximityInfo( + GRID_WIDTH, GRID_HEIGHT, getMinWidth(), getHeight(), getKeyWidth(), mKeys); } public int getProximityInfo() { - return mProximityInfo.getNativeProximityInfo(this); + return mProximityInfo.getNativeProximityInfo(); } public List<Key> getKeys() { @@ -219,8 +211,6 @@ public class Keyboard { public void setKeyWidth(int width) { mDefaultWidth = width; - final int threshold = (int) (width * SEARCH_DISTANCE); - mProximityThreshold = threshold * threshold; } /** @@ -365,34 +355,6 @@ public class Keyboard { return label; } - // TODO: Move this function to ProximityInfo and make this private. - public void computeNearestNeighbors() { - // Round-up so we don't have any pixels outside the grid - mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH; - mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT; - mGridNeighbors = new int[GRID_SIZE][]; - final int[] indices = new int[mKeys.size()]; - final int gridWidth = GRID_WIDTH * mCellWidth; - final int gridHeight = GRID_HEIGHT * mCellHeight; - final int threshold = mProximityThreshold; - for (int x = 0; x < gridWidth; x += mCellWidth) { - for (int y = 0; y < gridHeight; y += mCellHeight) { - final int centerX = x + mCellWidth / 2; - final int centerY = y + mCellHeight / 2; - int count = 0; - for (int i = 0; i < mKeys.size(); i++) { - final Key key = mKeys.get(i); - if (key.squaredDistanceToEdge(centerX, centerY) < threshold) - indices[count++] = i; - } - final int[] cell = new int[count]; - System.arraycopy(indices, 0, cell, 0, count); - mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell; - } - } - mProximityInfo.setProximityInfo(mGridNeighbors, getMinWidth(), getHeight(), mKeys); - } - /** * Returns the indices of the keys that are closest to the given point. * @param x the x-coordinate of the point @@ -401,14 +363,7 @@ public class Keyboard { * point is out of range, then an array of size zero is returned. */ public int[] getNearestKeys(int x, int y) { - if (mGridNeighbors == null) computeNearestNeighbors(); - if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) { - int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth); - if (index < GRID_SIZE) { - return mGridNeighbors[index]; - } - } - return EMPTY_INT_ARRAY; + return mProximityInfo.getNearestKeys(x, y); } /** diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index 7e67d6f6b..905f779c0 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -70,9 +70,4 @@ public interface KeyboardActionListener { * Called when user released a finger outside any key. */ public void onCancelInput(); - - /** - * Called when the user quickly moves the finger from up to down. - */ - public void onSwipeDown(); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 275e9d1fe..bb21d7a63 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -152,7 +152,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha boolean voiceButtonOnPrimary) { mSwitchState = SWITCH_STATE_ALPHA; try { - loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, false); + final boolean isSymbols = (mCurrentId != null) ? mCurrentId.isSymbolsKeyboard() : false; + loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, isSymbols); } catch (RuntimeException e) { // Get KeyboardId to record which keyboard has been failed to load. final KeyboardId id = getKeyboardId(attribute, false); @@ -763,7 +764,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } mKeyboardView = (LatinKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); - mKeyboardView.setOnKeyboardActionListener(mInputMethodService); + mKeyboardView.setKeyboardActionListener(mInputMethodService); // This always needs to be set since the accessibility state can // potentially change without the input view being re-created. diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index d1345db9d..e31aa8478 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -331,7 +331,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mPreviewText = null; mShowKeyPreviewPopup = false; } - // TODO: Use Theme (android.R.styleable.Theme_backgroundDimAmount) mBackgroundDimAmount = a.getFloat(R.styleable.KeyboardView_backgroundDimAmount, 0.5f); a.recycle(); @@ -350,12 +349,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { return a.getFraction(index, 1000, 1000, 1) / 1000.0f; } - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - // TODO: Should notify InputMethodService instead? - KeyboardSwitcher.getInstance().onSizeChanged(); - } - /** * Attaches a keyboard to this view. The keyboard can be switched at any time and the * view will re-layout itself to accommodate the keyboard. diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java index c8cfb43e3..b5b623223 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; @@ -33,9 +34,10 @@ import android.widget.PopupWindow; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; +import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; +import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.keyboard.internal.MiniKeyboardBuilder; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; -import com.android.inputmethod.keyboard.internal.SwipeTracker; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; @@ -49,7 +51,7 @@ import java.util.WeakHashMap; * @attr ref R.styleable#KeyboardView_verticalCorrection * @attr ref R.styleable#KeyboardView_popupLayout */ -public class LatinKeyboardBaseView extends KeyboardView { +public class LatinKeyboardBaseView extends KeyboardView implements PointerTracker.KeyEventHandler { private static final String TAG = LatinKeyboardBaseView.class.getSimpleName(); private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = true; @@ -64,7 +66,8 @@ public class LatinKeyboardBaseView extends KeyboardView { // Mini keyboard private PopupWindow mPopupWindow; - private PopupPanel mPopupMiniKeyboardPanel; + private PopupPanel mPopupPanel; + private int mPopupPanelPointerTrackerId; private final WeakHashMap<Key, PopupPanel> mPopupPanelCache = new WeakHashMap<Key, PopupPanel>(); @@ -74,7 +77,7 @@ public class LatinKeyboardBaseView extends KeyboardView { private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>(); // TODO: Let the PointerTracker class manage this pointer queue - private final PointerTrackerQueue mPointerQueue = new PointerTrackerQueue(); + private final PointerTrackerQueue mPointerQueue; private final boolean mHasDistinctMultitouch; private int mOldPointerCount = 1; @@ -82,15 +85,13 @@ public class LatinKeyboardBaseView extends KeyboardView { protected KeyDetector mKeyDetector; - // Swipe gesture detector + // To detect double tap. protected GestureDetector mGestureDetector; - private final SwipeTracker mSwipeTracker = new SwipeTracker(); - private final int mSwipeThreshold; - private final boolean mDisambiguateSwipe; private final KeyTimerHandler mKeyTimerHandler = new KeyTimerHandler(this); - public static class KeyTimerHandler extends StaticInnerHandlerWrapper<LatinKeyboardBaseView> { + private static class KeyTimerHandler extends StaticInnerHandlerWrapper<LatinKeyboardBaseView> + implements TimerProxy { private static final int MSG_REPEAT_KEY = 1; private static final int MSG_LONGPRESS_KEY = 2; private static final int MSG_LONGPRESS_SHIFT_KEY = 3; @@ -120,6 +121,7 @@ public class LatinKeyboardBaseView extends KeyboardView { } } + @Override public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) { mInKeyRepeat = true; sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0, tracker), delay); @@ -134,11 +136,13 @@ public class LatinKeyboardBaseView extends KeyboardView { return mInKeyRepeat; } + @Override public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) { cancelLongPressTimers(); sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay); } + @Override public void startLongPressShiftTimer(long delay, int keyIndex, PointerTracker tracker) { cancelLongPressTimers(); if (ENABLE_CAPSLOCK_BY_LONGPRESS) { @@ -147,11 +151,13 @@ public class LatinKeyboardBaseView extends KeyboardView { } } + @Override public void cancelLongPressTimers() { removeMessages(MSG_LONGPRESS_KEY); removeMessages(MSG_LONGPRESS_SHIFT_KEY); } + @Override public void cancelKeyTimers() { cancelKeyRepeatTimer(); cancelLongPressTimers(); @@ -172,6 +178,52 @@ public class LatinKeyboardBaseView extends KeyboardView { } } + private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener { + private boolean mProcessingShiftDoubleTapEvent = false; + + @Override + public boolean onDoubleTap(MotionEvent firstDown) { + final Keyboard keyboard = getKeyboard(); + if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard instanceof LatinKeyboard + && ((LatinKeyboard) keyboard).isAlphaKeyboard()) { + final int pointerIndex = firstDown.getActionIndex(); + final int id = firstDown.getPointerId(pointerIndex); + final PointerTracker tracker = getPointerTracker(id); + // If the first down event is on shift key. + if (tracker.isOnShiftKey((int) firstDown.getX(), (int) firstDown.getY())) { + mProcessingShiftDoubleTapEvent = true; + return true; + } + } + mProcessingShiftDoubleTapEvent = false; + return false; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent secondTap) { + if (mProcessingShiftDoubleTapEvent + && secondTap.getAction() == MotionEvent.ACTION_DOWN) { + final MotionEvent secondDown = secondTap; + final int pointerIndex = secondDown.getActionIndex(); + final int id = secondDown.getPointerId(pointerIndex); + final PointerTracker tracker = getPointerTracker(id); + // If the second down event is also on shift key. + if (tracker.isOnShiftKey((int) secondDown.getX(), (int) secondDown.getY())) { + // Detected a double tap on shift key. If we are in the ignoring double tap + // mode, it means we have already turned off caps lock in + // {@link KeyboardSwitcher#onReleaseShift} . + final boolean ignoringDoubleTap = mKeyTimerHandler.isIgnoringDoubleTap(); + if (!ignoringDoubleTap) + onDoubleTapShiftKey(tracker); + return true; + } + // Otherwise these events should not be handled as double tap. + mProcessingShiftDoubleTapEvent = false; + } + return mProcessingShiftDoubleTapEvent; + } + } + public LatinKeyboardBaseView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.keyboardViewStyle); } @@ -183,91 +235,23 @@ public class LatinKeyboardBaseView extends KeyboardView { attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); mVerticalCorrection = a.getDimensionPixelOffset( R.styleable.KeyboardView_verticalCorrection, 0); - mPopupLayout = a.getResourceId(R.styleable.KeyboardView_popupLayout, 0); - // TODO: Use Theme (android.R.styleable.Theme_backgroundDimAmount) a.recycle(); final Resources res = getResources(); - final float keyHysteresisDistance = res.getDimension(R.dimen.key_hysteresis_distance); mKeyDetector = new KeyDetector(keyHysteresisDistance); - mSwipeThreshold = (int) (500 * res.getDisplayMetrics().density); - // TODO: Refer to frameworks/base/core/res/res/values/config.xml - mDisambiguateSwipe = res.getBoolean(R.bool.config_swipeDisambiguation); - - GestureDetector.SimpleOnGestureListener listener = - new GestureDetector.SimpleOnGestureListener() { - private boolean mProcessingShiftDoubleTapEvent = false; - - @Override - public boolean onFling(MotionEvent me1, MotionEvent me2, float velocityX, - float velocityY) { - final float absX = Math.abs(velocityX); - final float absY = Math.abs(velocityY); - float deltaY = me2.getY() - me1.getY(); - int travelY = getHeight() / 2; // Half the keyboard height - mSwipeTracker.computeCurrentVelocity(1000); - final float endingVelocityY = mSwipeTracker.getYVelocity(); - if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) { - if (mDisambiguateSwipe && endingVelocityY >= velocityY / 4) { - onSwipeDown(); - return true; - } - } - return false; - } - - @Override - public boolean onDoubleTap(MotionEvent firstDown) { - final Keyboard keyboard = getKeyboard(); - if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard instanceof LatinKeyboard - && ((LatinKeyboard) keyboard).isAlphaKeyboard()) { - final int pointerIndex = firstDown.getActionIndex(); - final int id = firstDown.getPointerId(pointerIndex); - final PointerTracker tracker = getPointerTracker(id); - // If the first down event is on shift key. - if (tracker.isOnShiftKey((int)firstDown.getX(), (int)firstDown.getY())) { - mProcessingShiftDoubleTapEvent = true; - return true; - } - } - mProcessingShiftDoubleTapEvent = false; - return false; - } - - @Override - public boolean onDoubleTapEvent(MotionEvent secondTap) { - if (mProcessingShiftDoubleTapEvent - && secondTap.getAction() == MotionEvent.ACTION_DOWN) { - final MotionEvent secondDown = secondTap; - final int pointerIndex = secondDown.getActionIndex(); - final int id = secondDown.getPointerId(pointerIndex); - final PointerTracker tracker = getPointerTracker(id); - // If the second down event is also on shift key. - if (tracker.isOnShiftKey((int)secondDown.getX(), (int)secondDown.getY())) { - // Detected a double tap on shift key. If we are in the ignoring double tap - // mode, it means we have already turned off caps lock in - // {@link KeyboardSwitcher#onReleaseShift} . - final boolean ignoringDoubleTap = mKeyTimerHandler.isIgnoringDoubleTap(); - if (!ignoringDoubleTap) - onDoubleTapShiftKey(tracker); - return true; - } - // Otherwise these events should not be handled as double tap. - mProcessingShiftDoubleTapEvent = false; - } - return mProcessingShiftDoubleTapEvent; - } - }; final boolean ignoreMultitouch = true; - mGestureDetector = new GestureDetector(getContext(), listener, null, ignoreMultitouch); + mGestureDetector = new GestureDetector( + getContext(), new DoubleTapListener(), null, ignoreMultitouch); mGestureDetector.setIsLongpressEnabled(false); mHasDistinctMultitouch = context.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); + + mPointerQueue = mHasDistinctMultitouch ? new PointerTrackerQueue() : null; } public void startIgnoringDoubleTap() { @@ -275,10 +259,10 @@ public class LatinKeyboardBaseView extends KeyboardView { mKeyTimerHandler.startIgnoringDoubleTap(); } - public void setOnKeyboardActionListener(KeyboardActionListener listener) { + public void setKeyboardActionListener(KeyboardActionListener listener) { mKeyboardActionListener = listener; for (PointerTracker tracker : mPointerTrackers) { - tracker.setOnKeyboardActionListener(listener); + tracker.setKeyboardActionListener(listener); } } @@ -286,10 +270,32 @@ public class LatinKeyboardBaseView extends KeyboardView { * Returns the {@link KeyboardActionListener} object. * @return the listener attached to this keyboard */ - protected KeyboardActionListener getOnKeyboardActionListener() { + @Override + public KeyboardActionListener getKeyboardActionListener() { return mKeyboardActionListener; } + @Override + public KeyDetector getKeyDetector() { + return mKeyDetector; + } + + @Override + public DrawingProxy getDrawingProxy() { + return this; + } + + @Override + public TimerProxy getTimerProxy() { + return mKeyTimerHandler; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + // TODO: Should notify InputMethodService instead? + KeyboardSwitcher.getInstance().onSizeChanged(); + } + /** * Attaches a keyboard to this view. The keyboard can be switched at any time and the * view will re-layout itself to accommodate the keyboard. @@ -305,10 +311,10 @@ public class LatinKeyboardBaseView extends KeyboardView { // Remove any pending messages, except dismissing preview mKeyTimerHandler.cancelKeyTimers(); super.setKeyboard(keyboard); - mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), - -getPaddingTop() + mVerticalCorrection); + mKeyDetector.setKeyboard( + keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); for (PointerTracker tracker : mPointerTrackers) { - tracker.setKeyboard(keyboard, mKeyDetector); + tracker.setKeyDetector(mKeyDetector); } mKeyDetector.setProximityThreshold(keyboard.getMostCommonKeyWidth()); mPopupPanelCache.clear(); @@ -359,26 +365,24 @@ public class LatinKeyboardBaseView extends KeyboardView { 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(mPointerQueue); - } - return result; + return onLongPress(parentKey, tracker); } private void onLongPressShiftKey(PointerTracker tracker) { - tracker.onLongPressed(mPointerQueue); + tracker.onLongPressed(); mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0); } private void onDoubleTapShiftKey(@SuppressWarnings("unused") PointerTracker tracker) { // When shift key is double tapped, the first tap is correctly processed as usual tap. And // the second tap is treated as this double tap event, so that we need not mark tracker - // calling setAlreadyProcessed() nor remove the tracker from mPointerQueueueue. + // calling setAlreadyProcessed() nor remove the tracker from mPointerQueue. mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0); } @@ -394,39 +398,6 @@ public class LatinKeyboardBaseView extends KeyboardView { final PopupMiniKeyboardView miniKeyboardView = (PopupMiniKeyboardView)container.findViewById(R.id.mini_keyboard_view); - miniKeyboardView.setOnKeyboardActionListener(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 onSwipeDown() { - // Nothing to do. - } - @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 { @Override protected boolean needsToDimKeyboard() { - return mPopupMiniKeyboardPanel != null; + return mPopupPanel != null; } /** @@ -466,8 +437,14 @@ public class LatinKeyboardBaseView extends KeyboardView { // 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,17 +453,14 @@ public class LatinKeyboardBaseView extends KeyboardView { private PointerTracker getPointerTracker(final int id) { final ArrayList<PointerTracker> 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, - mHasDistinctMultitouch); - if (keyboard != null) - tracker.setKeyboard(keyboard, mKeyDetector); + mPointerQueue); if (listener != null) - tracker.setOnKeyboardActionListener(listener); + tracker.setKeyboardActionListener(listener); pointers.add(tracker); } @@ -494,10 +468,12 @@ public class LatinKeyboardBaseView extends KeyboardView { } 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(); } } @@ -520,11 +496,8 @@ public class LatinKeyboardBaseView extends KeyboardView { return true; } - // Track the last few movements to look for spurious swipes. - mSwipeTracker.addMovement(me); - // 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(); @@ -534,13 +507,13 @@ public class LatinKeyboardBaseView extends KeyboardView { 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()) { @@ -565,9 +538,9 @@ public class LatinKeyboardBaseView extends KeyboardView { // previous key. final int newKeyIndex = tracker.getKeyIndexOn(x, y); if (mOldKeyIndex != newKeyIndex) { - tracker.onDownEvent(x, y, eventTime, null); + tracker.onDownEvent(x, y, eventTime, this); if (action == MotionEvent.ACTION_UP) - tracker.onUpEvent(x, y, eventTime, null); + tracker.onUpEvent(x, y, eventTime); } } else if (pointerCount == 2 && oldPointerCount == 1) { // Single-touch to multi-touch transition. @@ -575,9 +548,9 @@ public class LatinKeyboardBaseView extends KeyboardView { final int lastX = tracker.getLastX(); final int lastY = tracker.getLastY(); mOldKeyIndex = tracker.getKeyIndexOn(lastX, lastY); - tracker.onUpEvent(lastX, lastY, eventTime, null); + tracker.onUpEvent(lastX, lastY, eventTime); } else if (pointerCount == 1 && oldPointerCount == 1) { - tracker.onTouchEvent(action, x, y, eventTime, null); + processMotionEvent(tracker, action, x, y, eventTime, this); } else { Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount + " (old " + oldPointerCount + ")"); @@ -585,34 +558,44 @@ public class LatinKeyboardBaseView extends KeyboardView { return true; } - final PointerTrackerQueue queue = mPointerQueue; 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, queue); + 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 { - final PointerTracker tracker = getPointerTracker(id); - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - tracker.onDownEvent(x, y, eventTime, queue); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - tracker.onUpEvent(x, y, eventTime, queue); - break; - case MotionEvent.ACTION_CANCEL: - tracker.onCancelEvent(x, y, eventTime, queue); - break; - } + processMotionEvent(getPointerTracker(id), action, x, y, eventTime, this); } return true; } - protected void onSwipeDown() { - mKeyboardActionListener.onSwipeDown(); + private static void processMotionEvent(PointerTracker tracker, int action, int x, int y, + long eventTime, PointerTracker.KeyEventHandler handler) { + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + tracker.onDownEvent(x, y, eventTime, handler); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + tracker.onUpEvent(x, y, eventTime); + break; + case MotionEvent.ACTION_MOVE: + tracker.onMoveEvent(x, y, eventTime); + break; + case MotionEvent.ACTION_CANCEL: + tracker.onCancelEvent(x, y, eventTime); + break; + } } @Override @@ -622,10 +605,11 @@ public class LatinKeyboardBaseView extends KeyboardView { 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 510bc16b4..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 { @@ -106,7 +108,7 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { } private boolean invokeOnKey(int primaryCode) { - getOnKeyboardActionListener().onCodeInput(primaryCode, null, + getKeyboardActionListener().onCodeInput(primaryCode, null, KeyboardActionListener.NOT_A_TOUCH_COORDINATE, KeyboardActionListener.NOT_A_TOUCH_COORDINATE); return true; diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java index 69005db57..1ec0dda15 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java @@ -37,7 +37,7 @@ public class MiniKeyboardKeyDetector extends KeyDetector { @Override public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { - final List<Key> keys = getKeys(); + final List<Key> keys = getKeyboard().getKeys(); final int touchX = getTouchX(x); final int touchY = getTouchY(y); diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 4ceabff4c..d23fb4aad 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -18,12 +18,8 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.res.Resources; -import android.os.SystemClock; import android.util.Log; -import android.view.MotionEvent; -import com.android.inputmethod.keyboard.LatinKeyboardBaseView.KeyTimerHandler; -import com.android.inputmethod.keyboard.internal.PointerTrackerKeyState; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; @@ -34,12 +30,38 @@ import java.util.List; public class PointerTracker { private static final String TAG = PointerTracker.class.getSimpleName(); - private static final boolean ENABLE_ASSERTION = false; private static final boolean DEBUG_EVENT = false; private static final boolean DEBUG_MOVE_EVENT = false; private static final boolean DEBUG_LISTENER = false; private static boolean DEBUG_MODE = LatinImeLogger.sDBG; + public interface KeyEventHandler { + /** + * Get KeyDetector object that is used for this PointerTracker. + * @return the KeyDetector object that is used for this PointerTracker + */ + public KeyDetector getKeyDetector(); + + /** + * Get KeyboardActionListener object that is used to register key code and so on. + * @return the KeyboardActionListner for this PointerTracker + */ + public KeyboardActionListener getKeyboardActionListener(); + + /** + * Get DrawingProxy object that is used for this PointerTracker. + * @return the DrawingProxy object that is used for this PointerTracker + */ + public DrawingProxy getDrawingProxy(); + + /** + * Get TimerProxy object that handles key repeat and long press timer event for this + * PointerTracker. + * @return the TimerProxy object that handles key repeat and long press timer event. + */ + public TimerProxy getTimerProxy(); + } + public interface DrawingProxy { public void invalidateKey(Key key); public void showKeyPreview(int keyIndex, PointerTracker tracker); @@ -47,6 +69,14 @@ public class PointerTracker { public void dismissKeyPreview(PointerTracker tracker); } + public interface TimerProxy { + public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker); + public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker); + public void startLongPressShiftTimer(long delay, int keyIndex, PointerTracker tracker); + public void cancelLongPressTimers(); + public void cancelKeyTimers(); + } + public final int mPointerId; // Timing constants @@ -54,12 +84,12 @@ public class PointerTracker { private final int mLongPressKeyTimeout; private final int mLongPressShiftKeyTimeout; - private final DrawingProxy mDrawingProxy; - private final KeyTimerHandler mKeyTimerHandler; + private DrawingProxy mDrawingProxy; + private TimerProxy mTimerProxy; + private final PointerTrackerQueue mPointerTrackerQueue; private KeyDetector mKeyDetector; private KeyboardActionListener mListener = EMPTY_LISTENER; private final KeyboardSwitcher mKeyboardSwitcher; - private final boolean mHasDistinctMultitouch; private final boolean mConfigSlidingKeyInputEnabled; private final int mTouchNoiseThresholdMillis; @@ -69,7 +99,19 @@ public class PointerTracker { private List<Key> mKeys; private int mKeyQuarterWidthSquared; - private final PointerTrackerKeyState mKeyState; + // The position and time at which first down event occurred. + private long mDownTime; + private long mUpTime; + + // The current key index where this pointer is. + private int mKeyIndex = KeyDetector.NOT_A_KEY; + // The position where mKeyIndex was recognized for the first time. + private int mKeyX; + private int mKeyY; + + // Last pointer position. + private int mLastX; + private int mLastY; // true if keyboard layout has been changed. private boolean mKeyboardLayoutHasBeenChanged; @@ -107,21 +149,18 @@ public class PointerTracker { public void onTextInput(CharSequence text) {} @Override public void onCancelInput() {} - @Override - public void onSwipeDown() {} }; - public PointerTracker(int id, Context context, KeyTimerHandler keyTimerHandler, - KeyDetector keyDetector, DrawingProxy drawingProxy, boolean hasDistinctMultitouch) { - if (drawingProxy == null || keyTimerHandler == null || keyDetector == null) + public PointerTracker(int id, Context context, TimerProxy timerProxy, KeyDetector keyDetector, + DrawingProxy drawingProxy, PointerTrackerQueue queue) { + if (drawingProxy == null || timerProxy == null || keyDetector == null) throw new NullPointerException(); mPointerId = id; mDrawingProxy = drawingProxy; - mKeyTimerHandler = keyTimerHandler; - mKeyDetector = keyDetector; + mTimerProxy = timerProxy; + mPointerTrackerQueue = queue; // This is null for non-distinct multi-touch device. + setKeyDetectorInner(keyDetector); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); - mKeyState = new PointerTrackerKeyState(keyDetector); - mHasDistinctMultitouch = hasDistinctMultitouch; final Resources res = context.getResources(); mConfigSlidingKeyInputEnabled = res.getBoolean(R.bool.config_sliding_key_input_enabled); mDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start); @@ -135,7 +174,7 @@ public class PointerTracker { mSubtypeSwitcher = SubtypeSwitcher.getInstance(); } - public void setOnKeyboardActionListener(KeyboardActionListener listener) { + public void setKeyboardActionListener(KeyboardActionListener listener) { mListener = listener; } @@ -196,15 +235,18 @@ public class PointerTracker { mListener.onCancelInput(); } - public void setKeyboard(Keyboard keyboard, KeyDetector keyDetector) { - if (keyboard == null || keyDetector == null) - throw new NullPointerException(); - mKeyboard = keyboard; - mKeys = keyboard.getKeys(); + public void setKeyDetectorInner(KeyDetector keyDetector) { mKeyDetector = keyDetector; - mKeyState.setKeyDetector(keyDetector); - final int keyQuarterWidth = keyboard.getKeyWidth() / 4; + mKeyboard = keyDetector.getKeyboard(); + mKeys = mKeyboard.getKeys(); + final int keyQuarterWidth = mKeyboard.getKeyWidth() / 4; mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; + } + + public void setKeyDetector(KeyDetector keyDetector) { + if (keyDetector == null) + throw new NullPointerException(); + setKeyDetectorInner(keyDetector); // Mark that keyboard layout has been changed. mKeyboardLayoutHasBeenChanged = true; } @@ -232,7 +274,7 @@ public class PointerTracker { } public boolean isModifier() { - return isModifierInternal(mKeyState.getKeyIndex()); + return isModifierInternal(mKeyIndex); } private boolean isOnModifierKey(int x, int y) { @@ -254,7 +296,7 @@ public class PointerTracker { } public void setReleasedKeyGraphics() { - setReleasedKeyGraphics(mKeyState.getKeyIndex()); + setReleasedKeyGraphics(mKeyIndex); } private void setReleasedKeyGraphics(int keyIndex) { @@ -273,44 +315,59 @@ public class PointerTracker { } } - private void checkAssertion(PointerTrackerQueue queue) { - if (mHasDistinctMultitouch && queue == null) - throw new RuntimeException( - "PointerTrackerQueue must be passed on distinct multi touch device"); - if (!mHasDistinctMultitouch && queue != null) - throw new RuntimeException( - "PointerTrackerQueue must be null on non-distinct multi touch device"); - } - - public void onTouchEvent(int action, int x, int y, long eventTime, PointerTrackerQueue queue) { - switch (action) { - case MotionEvent.ACTION_MOVE: - onMoveEvent(x, y, eventTime, queue); - break; - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - onDownEvent(x, y, eventTime, queue); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - onUpEvent(x, y, eventTime, queue); - break; - case MotionEvent.ACTION_CANCEL: - onCancelEvent(x, y, eventTime, queue); - break; - } + public int getLastX() { + return mLastX; + } + + public int getLastY() { + return mLastY; } - public void onDownEvent(int x, int y, long eventTime, PointerTrackerQueue queue) { - if (ENABLE_ASSERTION) checkAssertion(queue); + public long getDownTime() { + return mDownTime; + } + + private int onDownKey(int x, int y, long eventTime) { + mDownTime = eventTime; + return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); + } + + private int onMoveKeyInternal(int x, int y) { + mLastX = x; + mLastY = y; + return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + } + + private int onMoveKey(int x, int y) { + return onMoveKeyInternal(x, y); + } + + private int onMoveToNewKey(int keyIndex, int x, int y) { + mKeyIndex = keyIndex; + mKeyX = x; + mKeyY = y; + return keyIndex; + } + + private int onUpKey(int x, int y, long eventTime) { + mUpTime = eventTime; + mKeyIndex = KeyDetector.NOT_A_KEY; + return onMoveKeyInternal(x, y); + } + + public void onDownEvent(int x, int y, long eventTime, KeyEventHandler handler) { if (DEBUG_EVENT) printTouchEvent("onDownEvent:", x, y, eventTime); + mDrawingProxy = handler.getDrawingProxy(); + mTimerProxy = handler.getTimerProxy(); + setKeyboardActionListener(handler.getKeyboardActionListener()); + setKeyDetectorInner(handler.getKeyDetector()); // Naive up-to-down noise filter. - final long deltaT = eventTime - mKeyState.getUpTime(); + final long deltaT = eventTime - mUpTime; if (deltaT < mTouchNoiseThresholdMillis) { - final int dx = x - mKeyState.getLastX(); - final int dy = y - mKeyState.getLastY(); + final int dx = x - mLastX; + final int dy = y - mLastY; final int distanceSquared = (dx * dx + dy * dy); if (distanceSquared < mTouchNoiseThresholdDistanceSquared) { if (DEBUG_MODE) @@ -321,6 +378,7 @@ public class PointerTracker { } } + final PointerTrackerQueue queue = mPointerTrackerQueue; if (queue != null) { if (isOnModifierKey(x, y)) { // Before processing a down event of modifier key, all pointers already being @@ -333,7 +391,7 @@ public class PointerTracker { } private void onDownEventInternal(int x, int y, long eventTime) { - int keyIndex = mKeyState.onDownKey(x, y, eventTime); + int keyIndex = onDownKey(x, y, eventTime); // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding // from modifier key, or 3) this pointer is on mini-keyboard. mIsAllowedSlidingKeyInput = mConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex) @@ -349,7 +407,7 @@ public class PointerTracker { // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new // keyboard layout. if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), false)) - keyIndex = mKeyState.onDownKey(x, y, eventTime); + keyIndex = onDownKey(x, y, eventTime); startRepeatKey(keyIndex); startLongPressTimer(keyIndex); @@ -364,25 +422,23 @@ public class PointerTracker { mIsInSlidingKeyInput = true; } - public void onMoveEvent(int x, int y, long eventTime, PointerTrackerQueue queue) { - if (ENABLE_ASSERTION) checkAssertion(queue); + public void onMoveEvent(int x, int y, long eventTime) { if (DEBUG_MOVE_EVENT) printTouchEvent("onMoveEvent:", x, y, eventTime); if (mKeyAlreadyProcessed) return; - final PointerTrackerKeyState keyState = mKeyState; // TODO: Remove this hacking code if (mIsInSlidingLanguageSwitch) { - ((LatinKeyboard)mKeyboard).updateSpacebarPreviewIcon(x - keyState.getKeyX()); + ((LatinKeyboard)mKeyboard).updateSpacebarPreviewIcon(x - mKeyX); showKeyPreview(mSpaceKeyIndex); return; } - final int lastX = keyState.getLastX(); - final int lastY = keyState.getLastY(); - final int oldKeyIndex = keyState.getKeyIndex(); + final int lastX = mLastX; + final int lastY = mLastY; + final int oldKeyIndex = mKeyIndex; final Key oldKey = getKey(oldKeyIndex); - int keyIndex = keyState.onMoveKey(x, y); + int keyIndex = onMoveKey(x, y); if (isValidKeyIndex(keyIndex)) { if (oldKey == null) { // The pointer has been slid in to the new key, but the finger was not on any keys. @@ -391,8 +447,8 @@ public class PointerTracker { // {@link #setKeyboard}. In those cases, we should update keyIndex according to the // new keyboard layout. if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) - keyIndex = keyState.onMoveKey(x, y); - keyState.onMoveToNewKey(keyIndex, x, y); + keyIndex = onMoveKey(x, y); + onMoveToNewKey(keyIndex, x, y); startLongPressTimer(keyIndex); showKeyPreview(keyIndex); setPressedKeyGraphics(keyIndex); @@ -403,15 +459,15 @@ public class PointerTracker { setReleasedKeyGraphics(oldKeyIndex); callListenerOnRelease(oldKey, oldKey.mCode, true); startSlidingKeyInput(oldKey); - mKeyTimerHandler.cancelKeyTimers(); + mTimerProxy.cancelKeyTimers(); startRepeatKey(keyIndex); if (mIsAllowedSlidingKeyInput) { // This onPress call may have changed keyboard layout. Those cases are detected // at {@link #setKeyboard}. In those cases, we should update keyIndex according // to the new keyboard layout. if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) - keyIndex = keyState.onMoveKey(x, y); - keyState.onMoveToNewKey(keyIndex, x, y); + keyIndex = onMoveKey(x, y); + onMoveToNewKey(keyIndex, x, y); startLongPressTimer(keyIndex); setPressedKeyGraphics(keyIndex); showKeyPreview(keyIndex); @@ -441,7 +497,7 @@ public class PointerTracker { final LatinKeyboard keyboard = ((LatinKeyboard)mKeyboard); if (mSubtypeSwitcher.useSpacebarLanguageSwitcher() && mSubtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) { - final int diff = x - keyState.getKeyX(); + final int diff = x - mKeyX; if (keyboard.shouldTriggerSpacebarSlidingLanguageSwitch(diff)) { // Detect start sliding language switch. mIsInSlidingLanguageSwitch = true; @@ -449,6 +505,7 @@ public class PointerTracker { keyboard.updateSpacebarPreviewIcon(diff); // Display spacebar slide language switcher. showKeyPreview(keyIndex); + final PointerTrackerQueue queue = mPointerTrackerQueue; if (queue != null) queue.releaseAllPointersExcept(this, eventTime, true); } @@ -461,9 +518,9 @@ public class PointerTracker { setReleasedKeyGraphics(oldKeyIndex); callListenerOnRelease(oldKey, oldKey.mCode, true); startSlidingKeyInput(oldKey); - mKeyTimerHandler.cancelLongPressTimers(); + mTimerProxy.cancelLongPressTimers(); if (mIsAllowedSlidingKeyInput) { - keyState.onMoveToNewKey(keyIndex, x, y); + onMoveToNewKey(keyIndex, x, y); } else { mKeyAlreadyProcessed = true; dismissKeyPreview(); @@ -472,11 +529,11 @@ public class PointerTracker { } } - public void onUpEvent(int x, int y, long eventTime, PointerTrackerQueue queue) { - if (ENABLE_ASSERTION) checkAssertion(queue); + public void onUpEvent(int x, int y, long eventTime) { if (DEBUG_EVENT) printTouchEvent("onUpEvent :", x, y, eventTime); + final PointerTrackerQueue queue = mPointerTrackerQueue; if (queue != null) { if (isModifier()) { // Before processing an up event of modifier key, all pointers already being @@ -502,20 +559,19 @@ public class PointerTracker { private void onUpEventInternal(int x, int y, long eventTime, boolean updateReleasedKeyGraphics) { - mKeyTimerHandler.cancelKeyTimers(); + mTimerProxy.cancelKeyTimers(); mDrawingProxy.cancelShowKeyPreview(this); mIsInSlidingKeyInput = false; - final PointerTrackerKeyState keyState = mKeyState; final int keyX, keyY; - if (isMajorEnoughMoveToBeOnNewKey(x, y, keyState.onMoveKey(x, y))) { + if (isMajorEnoughMoveToBeOnNewKey(x, y, onMoveKey(x, y))) { keyX = x; keyY = y; } else { // Use previous fixed key coordinates. - keyX = keyState.getKeyX(); - keyY = keyState.getKeyY(); + keyX = mKeyX; + keyY = mKeyY; } - final int keyIndex = keyState.onUpKey(keyX, keyY, eventTime); + final int keyIndex = onUpKey(keyX, keyY, eventTime); dismissKeyPreview(); if (updateReleasedKeyGraphics) setReleasedKeyGraphics(keyIndex); @@ -540,20 +596,21 @@ public class PointerTracker { } } - public void onLongPressed(PointerTrackerQueue queue) { + 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); } } - public void onCancelEvent(int x, int y, long eventTime, PointerTrackerQueue queue) { - if (ENABLE_ASSERTION) checkAssertion(queue); + public void onCancelEvent(int x, int y, long eventTime) { if (DEBUG_EVENT) printTouchEvent("onCancelEvt:", x, y, eventTime); + final PointerTrackerQueue queue = mPointerTrackerQueue; if (queue != null) { queue.releaseAllPointersExcept(this, eventTime, true); queue.remove(this); @@ -562,10 +619,10 @@ public class PointerTracker { } private void onCancelEventInternal() { - mKeyTimerHandler.cancelKeyTimers(); + mTimerProxy.cancelKeyTimers(); mDrawingProxy.cancelShowKeyPreview(this); dismissKeyPreview(); - setReleasedKeyGraphics(mKeyState.getKeyIndex()); + setReleasedKeyGraphics(mKeyIndex); mIsInSlidingKeyInput = false; } @@ -574,7 +631,7 @@ public class PointerTracker { if (key != null && key.mRepeatable) { dismissKeyPreview(); onRepeatKey(keyIndex); - mKeyTimerHandler.startKeyRepeatTimer(mDelayBeforeKeyRepeatStart, keyIndex, this); + mTimerProxy.startKeyRepeatTimer(mDelayBeforeKeyRepeatStart, keyIndex, this); mIsRepeatableKey = true; } else { mIsRepeatableKey = false; @@ -588,22 +645,10 @@ public class PointerTracker { } } - public int getLastX() { - return mKeyState.getLastX(); - } - - public int getLastY() { - return mKeyState.getLastY(); - } - - public long getDownTime() { - return mKeyState.getDownTime(); - } - private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, int newKey) { if (mKeys == null || mKeyDetector == null) throw new NullPointerException("keyboard and/or key detector not set"); - int curKey = mKeyState.getKeyIndex(); + int curKey = mKeyIndex; if (newKey == curKey) { return false; } else if (isValidKeyIndex(curKey)) { @@ -640,16 +685,16 @@ public class PointerTracker { private void startLongPressTimer(int keyIndex) { Key key = getKey(keyIndex); if (key.mCode == Keyboard.CODE_SHIFT) { - mKeyTimerHandler.startLongPressShiftTimer(mLongPressShiftKeyTimeout, keyIndex, this); + mTimerProxy.startLongPressShiftTimer(mLongPressShiftKeyTimeout, keyIndex, this); } else if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { // We need not start long press timer on the key which has manual temporary upper case // code defined and the keyboard is in manual temporary upper case mode. return; } else if (mKeyboardSwitcher.isInMomentarySwitchState()) { // We use longer timeout for sliding finger input started from the symbols mode key. - mKeyTimerHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this); + mTimerProxy.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this); } else { - mKeyTimerHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this); + mTimerProxy.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this); } } diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java index 959427aad..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,11 +106,42 @@ 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. + } + + @Override public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { // Mini keyboard needs no pop-up key preview displayed, so we pass always false with a // delay of 0. The delay does not matter actually since the popup is not shown anyway. @@ -65,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(); @@ -94,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 386e11f2c..f94d1c562 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupPanel.java +++ b/java/src/com/android/inputmethod/keyboard/PopupPanel.java @@ -16,10 +16,9 @@ package com.android.inputmethod.keyboard; -import android.view.MotionEvent; import android.widget.PopupWindow; -public interface PopupPanel { +public interface PopupPanel extends PointerTracker.KeyEventHandler { /** * Show popup panel. * @param parentKeyboardView the parent KeyboardView that has the parent key. @@ -27,19 +26,20 @@ public interface PopupPanel { * @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); } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index 33acc6907..aadedc69d 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -23,15 +23,35 @@ import java.util.List; public class ProximityInfo { public static final int MAX_PROXIMITY_CHARS_SIZE = 16; + /** Number of key widths from current touch point to search for nearest keys. */ + private static float SEARCH_DISTANCE = 1.2f; + private static final int[] EMPTY_INT_ARRAY = new int[0]; private final int mGridWidth; private final int mGridHeight; private final int mGridSize; + private final int mCellWidth; + private final int mCellHeight; + // TODO: Find a proper name for mKeyboardMinWidth + private final int mKeyboardMinWidth; + private final int mKeyboardHeight; + private final int[][] mGridNeighbors; - ProximityInfo(int gridWidth, int gridHeight) { + ProximityInfo( + int gridWidth, int gridHeight, int minWidth, int height, int keyWidth, List<Key> keys) { mGridWidth = gridWidth; mGridHeight = gridHeight; mGridSize = mGridWidth * mGridHeight; + mCellWidth = (minWidth + mGridWidth - 1) / mGridWidth; + mCellHeight = (height + mGridHeight - 1) / mGridHeight; + mKeyboardMinWidth = minWidth; + mKeyboardHeight = height; + mGridNeighbors = new int[mGridSize][]; + if (minWidth == 0 || height == 0) { + // No proximity required. Keyboard might be mini keyboard. + return; + } + computeNearestNeighbors(keyWidth, keys); } private int mNativeProximityInfo; @@ -42,7 +62,7 @@ public class ProximityInfo { int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray); private native void releaseProximityInfoNative(int nativeProximityInfo); - public final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth, + private final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth, int keyboardHeight, List<Key> keys) { int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE]; Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE); @@ -57,12 +77,7 @@ public class ProximityInfo { keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, proximityCharsArray); } - // TODO: Get rid of this function's input (keyboard). - public int getNativeProximityInfo(Keyboard keyboard) { - if (mNativeProximityInfo == 0) { - // TODO: Move this function to ProximityInfo and make this private. - keyboard.computeNearestNeighbors(); - } + public int getNativeProximityInfo() { return mNativeProximityInfo; } @@ -77,4 +92,42 @@ public class ProximityInfo { super.finalize(); } } + + private void computeNearestNeighbors(int defaultWidth, List<Key> keys) { + final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE); + final int threshold = thresholdBase * thresholdBase; + // Round-up so we don't have any pixels outside the grid + final int[] indices = new int[keys.size()]; + final int gridWidth = mGridWidth * mCellWidth; + final int gridHeight = mGridHeight * mCellHeight; + for (int x = 0; x < gridWidth; x += mCellWidth) { + for (int y = 0; y < gridHeight; y += mCellHeight) { + final int centerX = x + mCellWidth / 2; + final int centerY = y + mCellHeight / 2; + int count = 0; + for (int i = 0; i < keys.size(); i++) { + final Key key = keys.get(i); + if (key.squaredDistanceToEdge(centerX, centerY) < threshold) + indices[count++] = i; + } + final int[] cell = new int[count]; + System.arraycopy(indices, 0, cell, 0, count); + mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = cell; + } + } + setProximityInfo(mGridNeighbors, mKeyboardMinWidth, mKeyboardHeight, keys); + } + + public int[] getNearestKeys(int x, int y) { + if (mGridNeighbors == null) { + return EMPTY_INT_ARRAY; + } + if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) { + int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth); + if (index < mGridSize) { + return mGridNeighbors[index]; + } + } + return EMPTY_INT_ARRAY; + } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index 1530fed6f..535a6954c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -34,21 +34,22 @@ public class KeyboardIconsSet { private static final int ICON_TO_SYMBOL_KEY = 2; private static final int ICON_TO_SYMBOL_KEY_WITH_SHORTCUT = 3; private static final int ICON_DELETE_KEY = 4; - private static final int ICON_SETTINGS_KEY = 5; - private static final int ICON_SHORTCUT_KEY = 6; - private static final int ICON_SPACE_KEY = 7; - private static final int ICON_RETURN_KEY = 8; - private static final int ICON_SEARCH_KEY = 9; - private static final int ICON_TAB_KEY = 10; + private static final int ICON_DELETE_RTL_KEY = 5; + private static final int ICON_SETTINGS_KEY = 6; + private static final int ICON_SHORTCUT_KEY = 7; + private static final int ICON_SPACE_KEY = 8; + private static final int ICON_RETURN_KEY = 9; + private static final int ICON_SEARCH_KEY = 10; + private static final int ICON_TAB_KEY = 11; // This should be aligned with Keyboard.keyIconShifted enum. - private static final int ICON_SHIFTED_SHIFT_KEY = 11; + private static final int ICON_SHIFTED_SHIFT_KEY = 12; // This should be aligned with Keyboard.keyIconPreview enum. - private static final int ICON_PREVIEW_SPACE_KEY = 12; - private static final int ICON_PREVIEW_TAB_KEY = 13; - private static final int ICON_PREVIEW_SETTINGS_KEY = 14; - private static final int ICON_PREVIEW_SHORTCUT_KEY = 15; + private static final int ICON_PREVIEW_SPACE_KEY = 13; + private static final int ICON_PREVIEW_TAB_KEY = 14; + private static final int ICON_PREVIEW_SETTINGS_KEY = 15; + private static final int ICON_PREVIEW_SHORTCUT_KEY = 16; - private static final int ICON_LAST = 15; + private static final int ICON_LAST = 16; private final Drawable mIcons[] = new Drawable[ICON_LAST + 1]; @@ -62,6 +63,8 @@ public class KeyboardIconsSet { return ICON_TO_SYMBOL_KEY_WITH_SHORTCUT; case R.styleable.Keyboard_iconDeleteKey: return ICON_DELETE_KEY; + case R.styleable.Keyboard_iconDeleteRtlKey: + return ICON_DELETE_RTL_KEY; case R.styleable.Keyboard_iconSettingsKey: return ICON_SETTINGS_KEY; case R.styleable.Keyboard_iconShortcutKey: diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerKeyState.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerKeyState.java deleted file mode 100644 index 6e2b60c30..000000000 --- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerKeyState.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2010 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.internal; - -import com.android.inputmethod.keyboard.KeyDetector; -import com.android.inputmethod.keyboard.PointerTracker; - -/** - * This class keeps track of a key index and a position where {@link PointerTracker} is. - */ -public class PointerTrackerKeyState { - private KeyDetector mKeyDetector; - - // The position and time at which first down event occurred. - private long mDownTime; - private long mUpTime; - - // The current key index where this pointer is. - private int mKeyIndex = KeyDetector.NOT_A_KEY; - // The position where mKeyIndex was recognized for the first time. - private int mKeyX; - private int mKeyY; - - // Last pointer position. - private int mLastX; - private int mLastY; - - public PointerTrackerKeyState(KeyDetector keyDetecor) { - mKeyDetector = keyDetecor; - } - - public void setKeyDetector(KeyDetector keyDetector) { - mKeyDetector = keyDetector; - } - - public int getKeyIndex() { - return mKeyIndex; - } - - public int getKeyX() { - return mKeyX; - } - - public int getKeyY() { - return mKeyY; - } - - public long getDownTime() { - return mDownTime; - } - - public long getUpTime() { - return mUpTime; - } - - public int getLastX() { - return mLastX; - } - - public int getLastY() { - return mLastY; - } - - public int onDownKey(int x, int y, long eventTime) { - mDownTime = eventTime; - return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); - } - - private int onMoveKeyInternal(int x, int y) { - mLastX = x; - mLastY = y; - return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); - } - - public int onMoveKey(int x, int y) { - return onMoveKeyInternal(x, y); - } - - public int onMoveToNewKey(int keyIndex, int x, int y) { - mKeyIndex = keyIndex; - mKeyX = x; - mKeyY = y; - return keyIndex; - } - - public int onUpKey(int x, int y, long eventTime) { - mUpTime = eventTime; - mKeyIndex = KeyDetector.NOT_A_KEY; - return onMoveKeyInternal(x, y); - } -} diff --git a/java/src/com/android/inputmethod/keyboard/internal/SwipeTracker.java b/java/src/com/android/inputmethod/keyboard/internal/SwipeTracker.java deleted file mode 100644 index 8d192c2f0..000000000 --- a/java/src/com/android/inputmethod/keyboard/internal/SwipeTracker.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2010 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.internal; - -import android.view.MotionEvent; - -public class SwipeTracker { - private static final int NUM_PAST = 4; - private static final int LONGEST_PAST_TIME = 200; - - final EventRingBuffer mBuffer = new EventRingBuffer(NUM_PAST); - - private float mYVelocity; - private float mXVelocity; - - public void addMovement(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mBuffer.clear(); - return; - } - long time = ev.getEventTime(); - final int count = ev.getHistorySize(); - for (int i = 0; i < count; i++) { - addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i), ev.getHistoricalEventTime(i)); - } - addPoint(ev.getX(), ev.getY(), time); - } - - private void addPoint(float x, float y, long time) { - final EventRingBuffer buffer = mBuffer; - while (buffer.size() > 0) { - long lastT = buffer.getTime(0); - if (lastT >= time - LONGEST_PAST_TIME) - break; - buffer.dropOldest(); - } - buffer.add(x, y, time); - } - - public void computeCurrentVelocity(int units) { - computeCurrentVelocity(units, Float.MAX_VALUE); - } - - public void computeCurrentVelocity(int units, float maxVelocity) { - final EventRingBuffer buffer = mBuffer; - final float oldestX = buffer.getX(0); - final float oldestY = buffer.getY(0); - final long oldestTime = buffer.getTime(0); - - float accumX = 0; - float accumY = 0; - final int count = buffer.size(); - for (int pos = 1; pos < count; pos++) { - final int dur = (int)(buffer.getTime(pos) - oldestTime); - if (dur == 0) continue; - float dist = buffer.getX(pos) - oldestX; - float vel = (dist / dur) * units; // pixels/frame. - if (accumX == 0) accumX = vel; - else accumX = (accumX + vel) * .5f; - - dist = buffer.getY(pos) - oldestY; - vel = (dist / dur) * units; // pixels/frame. - if (accumY == 0) accumY = vel; - else accumY = (accumY + vel) * .5f; - } - mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) - : Math.min(accumX, maxVelocity); - mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) - : Math.min(accumY, maxVelocity); - } - - public float getXVelocity() { - return mXVelocity; - } - - public float getYVelocity() { - return mYVelocity; - } - - public static class EventRingBuffer { - private final int bufSize; - private final float xBuf[]; - private final float yBuf[]; - private final long timeBuf[]; - private int top; // points new event - private int end; // points oldest event - private int count; // the number of valid data - - public EventRingBuffer(int max) { - this.bufSize = max; - xBuf = new float[max]; - yBuf = new float[max]; - timeBuf = new long[max]; - clear(); - } - - public void clear() { - top = end = count = 0; - } - - public int size() { - return count; - } - - // Position 0 points oldest event - private int index(int pos) { - return (end + pos) % bufSize; - } - - private int advance(int index) { - return (index + 1) % bufSize; - } - - public void add(float x, float y, long time) { - xBuf[top] = x; - yBuf[top] = y; - timeBuf[top] = time; - top = advance(top); - if (count < bufSize) { - count++; - } else { - end = advance(end); - } - } - - public float getX(int pos) { - return xBuf[index(pos)]; - } - - public float getY(int pos) { - return yBuf[index(pos)]; - } - - public long getTime(int pos) { - return timeBuf[index(pos)]; - } - - public void dropOldest() { - count--; - end = advance(end); - } - } -} diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 7ec18b38a..565b01d5a 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -333,7 +333,9 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo final TypedArray keyboardViewAttr = context.obtainStyledAttributes( attrs, R.styleable.KeyboardView, R.attr.keyboardViewStyle, R.style.KeyboardView); - final Drawable keyBackground = keyboardViewAttr.getDrawable( + final Drawable expandBackground = keyboardViewAttr.getDrawable( + R.styleable.KeyboardView_keyBackground); + final Drawable closeBackground = keyboardViewAttr.getDrawable( R.styleable.KeyboardView_keyBackground); final int keyTextColor = keyboardViewAttr.getColor( R.styleable.KeyboardView_keyTextColor, 0xFF000000); @@ -341,7 +343,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo mCandidatesPaneControl = (ViewGroup)findViewById(R.id.candidates_pane_control); mExpandCandidatesPane = (TextView)findViewById(R.id.expand_candidates_pane); - mExpandCandidatesPane.setBackgroundDrawable(keyBackground); + mExpandCandidatesPane.setBackgroundDrawable(expandBackground); mExpandCandidatesPane.setTextColor(keyTextColor); mExpandCandidatesPane.setOnClickListener(new OnClickListener() { @Override @@ -350,7 +352,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } }); mCloseCandidatesPane = (TextView)findViewById(R.id.close_candidates_pane); - mCloseCandidatesPane.setBackgroundDrawable(keyBackground); + mCloseCandidatesPane.setBackgroundDrawable(closeBackground); mCloseCandidatesPane.setTextColor(keyTextColor); mCloseCandidatesPane.setOnClickListener(new OnClickListener() { @Override @@ -704,6 +706,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo mCandidatesStrip.setVisibility(VISIBLE); mCandidatesStrip.removeAllViews(); mCandidatesPane.removeAllViews(); + closeCandidatesPane(); } private void hidePreview() { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a9f34c6c7..5304d830d 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -164,8 +164,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private boolean mIsSettingsSuggestionStripOn; private boolean mApplicationSpecifiedCompletionOn; - private final StringBuilder mComposing = new StringBuilder(); - private WordComposer mWord = new WordComposer(); + private final StringBuilder mComposingStringBuilder = new StringBuilder(); + private WordComposer mWordComposer = new WordComposer(); private CharSequence mBestWord; private boolean mHasUncommittedTypedChars; private boolean mHasDictionary; @@ -233,7 +233,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case MSG_UPDATE_OLD_SUGGESTIONS: latinIme.mRecorrection.fetchAndDisplayRecorrectionSuggestions( latinIme.mVoiceProxy, latinIme.mCandidateView, - latinIme.mSuggest, latinIme.mKeyboardSwitcher, latinIme.mWord, + latinIme.mSuggest, latinIme.mKeyboardSwitcher, latinIme.mWordComposer, latinIme.mHasUncommittedTypedChars, latinIme.mLastSelectionStart, latinIme.mLastSelectionEnd, latinIme.mSettingsValues.mWordSeparators); break; @@ -555,7 +555,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar inputView.closing(); mEnteredText = null; - mComposing.setLength(0); + mComposingStringBuilder.setLength(0); mHasUncommittedTypedChars = false; mDeleteCount = 0; mJustAddedMagicSpace = false; @@ -580,6 +580,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar switcher.updateShiftState(); } + if (mCandidateView != null) + mCandidateView.clear(); setSuggestionStripShownInternal(isCandidateStripVisible(), /* needsInputViewShown */ false); // Delay updating suggestions because keyboard input view may not be shown at this point. mHandler.postUpdateSuggestions(); @@ -715,16 +717,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final boolean selectionChanged = (newSelStart != candidatesEnd || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart; final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1; - if (((mComposing.length() > 0 && mHasUncommittedTypedChars) + if (((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars) || mVoiceProxy.isVoiceInputHighlighted()) && (selectionChanged || candidatesCleared)) { if (candidatesCleared) { // If the composing span has been cleared, save the typed word in the history for // recorrection before we reset the candidate strip. Then, we'll be able to show // suggestions for recorrection right away. - mRecorrection.saveRecorrectionSuggestion(mWord, mComposing); + mRecorrection.saveRecorrectionSuggestion(mWordComposer, mComposingStringBuilder); } - mComposing.setLength(0); + mComposingStringBuilder.setLength(0); mHasUncommittedTypedChars = false; if (isCursorTouchingWord()) { mHandler.cancelUpdateBigramPredictions(); @@ -738,15 +740,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.finishComposingText(); } mVoiceProxy.setVoiceInputHighlighted(false); - } else if (!mHasUncommittedTypedChars && !mExpectingUpdateSelection) { - if (TextEntryState.isAcceptedDefault() || TextEntryState.isSpaceAfterPicked()) { - if (TextEntryState.isAcceptedDefault()) - TextEntryState.reset(); - } + } else if (!mHasUncommittedTypedChars && !mExpectingUpdateSelection + && TextEntryState.isAcceptedDefault()) { + TextEntryState.reset(); } if (!mExpectingUpdateSelection) { - mJustAddedMagicSpace = false; // The user moved the cursor. - mJustReplacedDoubleSpace = false; + mJustAddedMagicSpace = false; // The user moved the cursor. + mJustReplacedDoubleSpace = false; } mExpectingUpdateSelection = false; mHandler.postUpdateShiftKeyState(); @@ -943,18 +943,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public void commitTyped(InputConnection inputConnection) { - if (mHasUncommittedTypedChars) { - mHasUncommittedTypedChars = false; - if (mComposing.length() > 0) { - if (inputConnection != null) { - inputConnection.commitText(mComposing, 1); - } - mCommittedLength = mComposing.length(); - TextEntryState.acceptedTyped(mComposing); - addToAutoAndUserBigramDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED); + if (!mHasUncommittedTypedChars) return; + mHasUncommittedTypedChars = false; + if (mComposingStringBuilder.length() > 0) { + if (inputConnection != null) { + inputConnection.commitText(mComposingStringBuilder, 1); } - updateSuggestions(); + mCommittedLength = mComposingStringBuilder.length(); + TextEntryState.acceptedTyped(mComposingStringBuilder); + addToAutoAndUserBigramDictionaries(mComposingStringBuilder, + AutoDictionary.FREQUENCY_FOR_TYPED); } + updateSuggestions(); } public boolean getCurrentAutoCapsState() { @@ -1183,12 +1183,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final boolean deleteChar = !mHasUncommittedTypedChars; if (mHasUncommittedTypedChars) { - final int length = mComposing.length(); + final int length = mComposingStringBuilder.length(); if (length > 0) { - mComposing.delete(length - 1, length); - mWord.deleteLast(); - ic.setComposingText(mComposing, 1); - if (mComposing.length() == 0) { + mComposingStringBuilder.delete(length - 1, length); + mWordComposer.deleteLast(); + ic.setComposingText(mComposingStringBuilder, 1); + if (mComposingStringBuilder.length() == 0) { mHasUncommittedTypedChars = false; } if (1 == length) { @@ -1278,9 +1278,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) { if (!mHasUncommittedTypedChars) { mHasUncommittedTypedChars = true; - mComposing.setLength(0); - mRecorrection.saveRecorrectionSuggestion(mWord, mBestWord); - mWord.reset(); + mComposingStringBuilder.setLength(0); + mRecorrection.saveRecorrectionSuggestion(mWordComposer, mBestWord); + mWordComposer.reset(); clearSuggestions(); } } @@ -1306,19 +1306,19 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } if (mHasUncommittedTypedChars) { - if (mComposing.length() == 0 && switcher.isAlphabetMode() + if (mComposingStringBuilder.length() == 0 && switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()) { - mWord.setFirstCharCapitalized(true); + mWordComposer.setFirstCharCapitalized(true); } - mComposing.append((char) code); - mWord.add(code, keyCodes, x, y); + mComposingStringBuilder.append((char) code); + mWordComposer.add(code, keyCodes, x, y); InputConnection ic = getCurrentInputConnection(); if (ic != null) { // If it's the first letter, make note of auto-caps state - if (mWord.size() == 1) { - mWord.setAutoCapitalized(getCurrentAutoCapsState()); + if (mWordComposer.size() == 1) { + mWordComposer.setAutoCapitalized(getCurrentAutoCapsState()); } - ic.setComposingText(mComposing, 1); + ic.setComposingText(mComposingStringBuilder, 1); } mHandler.postUpdateSuggestions(); } else { @@ -1386,7 +1386,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar TextEntryState.typedCharacter((char) primaryCode, true, x, y); if (pickedDefault) { - CharSequence typedWord = mWord.getTypedWord(); + CharSequence typedWord = mWordComposer.getTypedWord(); TextEntryState.backToAcceptedDefault(typedWord); if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) { InputConnectionCompatUtils.commitCorrection( @@ -1489,28 +1489,26 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar setPunctuationSuggestions(); return; } - showSuggestions(mWord); - } - private void showSuggestions(WordComposer word) { + final WordComposer wordComposer = mWordComposer; // TODO: May need a better way of retrieving previous word CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(), mSettingsValues.mWordSeparators); SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder( - mKeyboardSwitcher.getKeyboardView(), word, prevWord); + mKeyboardSwitcher.getKeyboardView(), wordComposer, prevWord); - boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection(); - final CharSequence typedWord = word.getTypedWord(); + boolean autoCorrectionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection(); + final CharSequence typedWord = wordComposer.getTypedWord(); // Here, we want to promote a whitelisted word if exists. final boolean typedWordValid = AutoCorrection.isValidWordForAutoCorrection( mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization()); if (mCorrectionMode == Suggest.CORRECTION_FULL || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) { - correctionAvailable |= typedWordValid; + autoCorrectionAvailable |= typedWordValid; } // Don't auto-correct words with multiple capital letter - correctionAvailable &= !word.isMostlyCaps(); - correctionAvailable &= !TextEntryState.isRecorrecting(); + autoCorrectionAvailable &= !wordComposer.isMostlyCaps(); + autoCorrectionAvailable &= !TextEntryState.isRecorrecting(); // Basically, we update the suggestion strip only when suggestion count > 1. However, // there is an exception: We update the suggestion strip whenever typed word's length @@ -1522,7 +1520,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid || mCandidateView.isShowingAddToDictionaryHint()) { builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion( - correctionAvailable); + autoCorrectionAvailable); } else { final SuggestedWords previousSuggestions = mCandidateView.getSuggestions(); if (previousSuggestions == mSettingsValues.mSuggestPuncList) @@ -1556,7 +1554,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar updateSuggestions(); } if (mBestWord != null && mBestWord.length() > 0) { - TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord, separatorCode); + TextEntryState.acceptedDefault(mWordComposer.getTypedWord(), mBestWord, separatorCode); mExpectingUpdateSelection = true; commitBestWord(mBestWord); // Add the word to the auto dictionary if it's not a known word @@ -1623,7 +1621,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!mHasUncommittedTypedChars) { // If we are not composing a word, then it was a suggestion inferred from // context - no user input. We should reset the word composer. - mWord.reset(); + mWordComposer.reset(); } mExpectingUpdateSelection = true; commitBestWord(suggestion); @@ -1633,9 +1631,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { addToOnlyBigramDictionary(suggestion, 1); } - LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(), - index, suggestions.mWords); - TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion); + LatinImeLogger.logOnManualSuggestion(mComposingStringBuilder.toString(), + suggestion.toString(), index, suggestions.mWords); + TextEntryState.acceptedSuggestion(mComposingStringBuilder.toString(), suggestion); // Follow it with a space if (mShouldInsertMagicSpace && !recorrecting) { sendMagicSpace(); @@ -1680,8 +1678,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } /** - * Commits the chosen word to the text field and saves it for later - * retrieval. + * Commits the chosen word to the text field and saves it for later retrieval. */ private void commitBestWord(CharSequence bestWord) { KeyboardSwitcher switcher = mKeyboardSwitcher; @@ -1694,7 +1691,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( this, bestWord, suggestedWords), 1); } - mRecorrection.saveRecorrectionSuggestion(mWord, bestWord); + mRecorrection.saveRecorrectionSuggestion(mWordComposer, bestWord); mHasUncommittedTypedChars = false; mCommittedLength = bestWord.length(); } @@ -1798,41 +1795,40 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void revertLastWord(boolean deleteChar) { - final int length = mComposing.length(); - if (!mHasUncommittedTypedChars && length > 0) { - final InputConnection ic = getCurrentInputConnection(); - final CharSequence punctuation = ic.getTextBeforeCursor(1, 0); - if (deleteChar) ic.deleteSurroundingText(1, 0); - int toDelete = mCommittedLength; - final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0); - if (!TextUtils.isEmpty(toTheLeft) - && mSettingsValues.isWordSeparator(toTheLeft.charAt(0))) { - toDelete--; - } - ic.deleteSurroundingText(toDelete, 0); - // Re-insert punctuation only when the deleted character was word separator and the - // composing text wasn't equal to the auto-corrected text. - if (deleteChar - && !TextUtils.isEmpty(punctuation) - && mSettingsValues.isWordSeparator(punctuation.charAt(0)) - && !TextUtils.equals(mComposing, toTheLeft)) { - ic.commitText(mComposing, 1); - TextEntryState.acceptedTyped(mComposing); - ic.commitText(punctuation, 1); - TextEntryState.typedCharacter(punctuation.charAt(0), true, - WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - // Clear composing text - mComposing.setLength(0); - } else { - mHasUncommittedTypedChars = true; - ic.setComposingText(mComposing, 1); - TextEntryState.backspace(); - } - mHandler.cancelUpdateBigramPredictions(); - mHandler.postUpdateSuggestions(); - } else { + if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) { sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + return; + } + + final InputConnection ic = getCurrentInputConnection(); + final CharSequence punctuation = ic.getTextBeforeCursor(1, 0); + if (deleteChar) ic.deleteSurroundingText(1, 0); + final CharSequence textToTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0); + final int toDeleteLength = (!TextUtils.isEmpty(textToTheLeft) + && mSettingsValues.isWordSeparator(textToTheLeft.charAt(0))) + ? mCommittedLength - 1 : mCommittedLength; + ic.deleteSurroundingText(toDeleteLength, 0); + + // Re-insert punctuation only when the deleted character was word separator and the + // composing text wasn't equal to the auto-corrected text. + if (deleteChar + && !TextUtils.isEmpty(punctuation) + && mSettingsValues.isWordSeparator(punctuation.charAt(0)) + && !TextUtils.equals(mComposingStringBuilder, textToTheLeft)) { + ic.commitText(mComposingStringBuilder, 1); + TextEntryState.acceptedTyped(mComposingStringBuilder); + ic.commitText(punctuation, 1); + TextEntryState.typedCharacter(punctuation.charAt(0), true, + WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + // Clear composing text + mComposingStringBuilder.setLength(0); + } else { + mHasUncommittedTypedChars = true; + ic.setComposingText(mComposingStringBuilder, 1); + TextEntryState.backspace(); } + mHandler.cancelUpdateBigramPredictions(); + mHandler.postUpdateSuggestions(); } private boolean revertDoubleSpace() { @@ -1861,7 +1857,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public boolean preferCapitalization() { - return mWord.isFirstCharCapitalized(); + return mWordComposer.isFirstCharCapitalized(); } // Notify that language or mode have been changed and toggleLanguage will update KeyboardID @@ -1890,12 +1886,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // subtype changes. if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) onRefreshKeyboard(); - } - - @Override - public void onSwipeDown() { - if (mSettingsValues.mSwipeDownDismissKeyboardEnabled) - handleClose(); } @Override @@ -1991,7 +1981,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public WordComposer getCurrentWord() { - return mWord; + return mWordComposer; } boolean isSoundOn() { @@ -2127,7 +2117,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final Printer p = new PrintWriterPrinter(fout); p.println("LatinIME state :"); p.println(" Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode()); - p.println(" mComposing=" + mComposing.toString()); + p.println(" mComposingStringBuilder=" + mComposingStringBuilder.toString()); p.println(" mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn); p.println(" mCorrectionMode=" + mCorrectionMode); p.println(" mHasUncommittedTypedChars=" + mHasUncommittedTypedChars); diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index d6b989073..33e9bc35f 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -18,8 +18,10 @@ package com.android.inputmethod.latin; import com.android.inputmethod.compat.CompatUtils; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.compat.VibratorCompatWrapper; +import com.android.inputmethodcommon.InputMethodSettingsActivity; import android.app.Activity; import android.app.AlertDialog; @@ -36,7 +38,6 @@ import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceActivity; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.speech.SpeechRecognizer; @@ -48,7 +49,7 @@ import android.widget.TextView; import java.util.Arrays; import java.util.Locale; -public class Settings extends PreferenceActivity +public class Settings extends InputMethodSettingsActivity implements SharedPreferences.OnSharedPreferenceChangeListener, DialogInterface.OnDismissListener, OnPreferenceClickListener { private static final String TAG = "Settings"; @@ -90,7 +91,6 @@ public class Settings extends PreferenceActivity public static class Values { // From resources: - public final boolean mSwipeDownDismissKeyboardEnabled; public final int mDelayBeforeFadeoutLanguageOnSpacebar; public final int mDelayUpdateSuggestions; public final int mDelayUpdateOldSuggestions; @@ -131,8 +131,6 @@ public class Settings extends PreferenceActivity } // Get the resources - mSwipeDownDismissKeyboardEnabled = res.getBoolean( - R.bool.config_swipe_down_dismiss_keyboard_enabled); mDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger( R.integer.config_delay_before_fadeout_language_on_spacebar); mDelayUpdateSuggestions = @@ -292,7 +290,6 @@ public class Settings extends PreferenceActivity } private PreferenceScreen mInputLanguageSelection; - private CheckBoxPreference mQuickFixes; private ListPreference mVoicePreference; private ListPreference mSettingsKeyPreference; private ListPreference mShowCorrectionSuggestionsPreference; @@ -334,13 +331,14 @@ public class Settings extends PreferenceActivity @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); + setInputMethodSettingsCategoryTitle(R.string.language_selection_title); + setSubtypeEnablerTitle(R.string.select_language); final Resources res = getResources(); final Context context = getActivityInternal(); addPreferencesFromResource(R.xml.prefs); mInputLanguageSelection = (PreferenceScreen) findPreference(PREF_SUBTYPES); mInputLanguageSelection.setOnPreferenceClickListener(this); - mQuickFixes = (CheckBoxPreference) findPreference(PREF_QUICK_FIXES); mVoicePreference = (ListPreference) findPreference(PREF_VOICE_SETTINGS_KEY); mSettingsKeyPreference = (ListPreference) findPreference(PREF_SETTINGS_KEY); mShowCorrectionSuggestionsPreference = @@ -387,6 +385,10 @@ public class Settings extends PreferenceActivity generalSettings.removePreference(findPreference(PREF_VIBRATE_ON)); } + if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { + generalSettings.removePreference(findPreference(PREF_SUBTYPES)); + } + final boolean showPopupOption = res.getBoolean( R.bool.config_enable_show_popup_on_keypress_option); if (!showPopupOption) { diff --git a/java/src/com/android/inputmethod/latin/SettingsActivity.java b/java/src/com/android/inputmethod/latin/SettingsActivity.java deleted file mode 100644 index 2da171a63..000000000 --- a/java/src/com/android/inputmethod/latin/SettingsActivity.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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.latin; - -public class SettingsActivity extends Settings { -} diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java index b6e261114..79b3bdebb 100644 --- a/java/src/com/android/inputmethod/latin/TextEntryState.java +++ b/java/src/com/android/inputmethod/latin/TextEntryState.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.Utils.RingCharBuffer; import android.util.Log; @@ -100,7 +101,7 @@ public class TextEntryState { } public static void typedCharacter(char c, boolean isSeparator, int x, int y) { - final boolean isSpace = (c == ' '); + final boolean isSpace = (c == Keyboard.CODE_SPACE); switch (sState) { case IN_WORD: if (isSpace || isSeparator) { |