diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 98eed264f..7ceff388e 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -53,6 +53,7 @@ import com.android.inputmethod.keyboard.internal.GestureFloatingPreviewText; import com.android.inputmethod.keyboard.internal.GestureTrailsPreview; import com.android.inputmethod.keyboard.internal.KeyDrawParams; import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; +import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper; import com.android.inputmethod.keyboard.internal.PreviewPlacerView; import com.android.inputmethod.keyboard.internal.SlidingKeyInputPreview; import com.android.inputmethod.latin.Constants; @@ -179,9 +180,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private int mGestureFloatingPreviewTextLingerTimeout; private KeyDetector mKeyDetector; - private final boolean mHasDistinctMultitouch; - private int mOldPointerCount = 1; - private Key mOldKey; + private final NonDistinctMultitouchHelper mNonDistinctMultitouchHelper; private final KeyTimerHandler mKeyTimerHandler; @@ -423,13 +422,16 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); + PointerTracker.init(getResources()); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final boolean forceNonDistinctMultitouch = prefs.getBoolean( DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false); final boolean hasDistinctMultitouch = context.getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); - mHasDistinctMultitouch = hasDistinctMultitouch && !forceNonDistinctMultitouch; - PointerTracker.init(getResources()); + .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT) + && !forceNonDistinctMultitouch; + mNonDistinctMultitouchHelper = hasDistinctMultitouch ? null + : new NonDistinctMultitouchHelper(); + mPreviewPlacerView = new PreviewPlacerView(context, attrs); final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes( @@ -1032,25 +1034,21 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack if (getKeyboard() == null) { return false; } - // TODO: Add multi-touch to single-touch event converter for non-distinct multi-touch - // device. + if (mNonDistinctMultitouchHelper != null) { + if (me.getPointerCount() > 1 && mKeyTimerHandler.isInKeyRepeat()) { + // Key repeating timer will be canceled if 2 or more keys are in action. + mKeyTimerHandler.cancelKeyRepeatTimer(); + } + // Non distinct multitouch screen support + mNonDistinctMultitouchHelper.processMotionEvent(me, this); + return true; + } return processMotionEvent(me); } public boolean processMotionEvent(final MotionEvent me) { - final boolean nonDistinctMultitouch = !mHasDistinctMultitouch; final int action = me.getActionMasked(); final int pointerCount = me.getPointerCount(); - final int oldPointerCount = mOldPointerCount; - mOldPointerCount = pointerCount; - - // TODO: cleanup this code into a multi-touch to single-touch event converter class? - // If the device does not have distinct multi-touch support panel, ignore all multi-touch - // events except a transition from/to single-touch. - if (nonDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) { - return true; - } - final long eventTime = me.getEventTime(); final int index = me.getActionIndex(); final int id = me.getPointerId(index); @@ -1068,50 +1066,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack me, action, eventTime, index, id, x, y); } - if (mKeyTimerHandler.isInKeyRepeat()) { - final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); - // Key repeating timer will be canceled if 2 or more keys are in action, and current - // event (UP or DOWN) is non-modifier key. - if (pointerCount > 1 && !tracker.isModifier()) { - mKeyTimerHandler.cancelKeyRepeatTimer(); - } - // Up event will pass through. - } - - // TODO: cleanup this code into a multi-touch to single-touch event converter class? - // Translate mutli-touch event to single-touch events on the device that has no distinct - // multi-touch panel. - if (nonDistinctMultitouch) { - // Use only main (id=0) pointer tracker. - final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); - if (pointerCount == 1 && oldPointerCount == 2) { - // Multi-touch to single touch transition. - // Send a down event for the latest pointer if the key is different from the - // previous key. - final Key newKey = tracker.getKeyOn(x, y); - if (mOldKey != newKey) { - tracker.onDownEvent(x, y, eventTime, this); - if (action == MotionEvent.ACTION_UP) { - tracker.onUpEvent(x, y, eventTime); - } - } - } else if (pointerCount == 2 && oldPointerCount == 1) { - // Single-touch to multi-touch transition. - // Send an up event for the last pointer. - final int[] lastCoords = CoordinateUtils.newInstance(); - mOldKey = tracker.getKeyOn( - CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords)); - tracker.onUpEvent( - CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime); - } else if (pointerCount == 1 && oldPointerCount == 1) { - tracker.processMotionEvent(action, x, y, eventTime, this); - } else { - Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount - + " (old " + oldPointerCount + ")"); - } - return true; - } - if (action == MotionEvent.ACTION_MOVE) { for (int i = 0; i < pointerCount; i++) { final int pointerId = me.getPointerId(i); diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 7079b4d02..bbaf96982 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -478,6 +478,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { mPointerId = id; mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints( id, sGestureStrokeParams, sGesturePreviewParams); + setKeyEventHandler(handler); + } + + private void setKeyEventHandler(final KeyEventHandler handler) { setKeyDetectorInner(handler.getKeyDetector()); mListener = handler.getKeyboardActionListener(); mDrawingProxy = handler.getDrawingProxy(); @@ -891,10 +895,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (DEBUG_EVENT) { printTouchEvent("onDownEvent:", x, y, eventTime); } - mDrawingProxy = handler.getDrawingProxy(); - mTimerProxy = handler.getTimerProxy(); - setKeyboardActionListener(handler.getKeyboardActionListener()); - setKeyDetectorInner(handler.getKeyDetector()); + setKeyEventHandler(handler); // Naive up-to-down noise filter. final long deltaT = eventTime - mUpTime; if (deltaT < sParams.mTouchNoiseThresholdTime) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java b/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java new file mode 100644 index 000000000..53fff6986 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013 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.util.Log; +import android.view.MotionEvent; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler; +import com.android.inputmethod.latin.utils.CoordinateUtils; + +public final class NonDistinctMultitouchHelper { + private static final String TAG = NonDistinctMultitouchHelper.class.getSimpleName(); + + private int mOldPointerCount = 1; + private Key mOldKey; + + public void processMotionEvent(final MotionEvent me, final KeyEventHandler keyEventHandler) { + final int pointerCount = me.getPointerCount(); + final int oldPointerCount = mOldPointerCount; + mOldPointerCount = pointerCount; + // Ignore continuous multitouch events because we can't trust the coordinates in mulitouch + // events. + if (pointerCount > 1 && oldPointerCount > 1) { + return; + } + + final int action = me.getActionMasked(); + final int index = me.getActionIndex(); + final long eventTime = me.getEventTime(); + final int x = (int)me.getX(index); + final int y = (int)me.getY(index); + // Use only main (id=0) pointer tracker. + final PointerTracker mainTracker = PointerTracker.getPointerTracker(0, keyEventHandler); + + // In single touch. + if (oldPointerCount == 1 && pointerCount == 1) { + mainTracker.processMotionEvent(action, x, y, eventTime, keyEventHandler); + return; + } + + // Single-touch to multi-touch transition. + if (oldPointerCount == 1 && pointerCount == 2) { + // Send an up event for the last pointer, be cause we can't trust the corrdinates of + // this multitouch event. + final int[] lastCoords = CoordinateUtils.newInstance(); + mainTracker.getLastCoordinates(lastCoords); + mOldKey = mainTracker.getKeyOn( + CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords)); + // TODO: Stop calling PointerTracker.onUpEvent directly. + mainTracker.onUpEvent( + CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime); + return; + } + + // Multi-touch to single touch transition. + if (oldPointerCount == 2 && pointerCount == 1) { + // Send a down event for the latest pointer if the key is different from the + // previous key. + final Key newKey = mainTracker.getKeyOn(x, y); + if (mOldKey != newKey) { + // TODO: Stop calling PointerTracker.onDownEvent directly. + mainTracker.onDownEvent(x, y, eventTime, keyEventHandler); + if (action == MotionEvent.ACTION_UP) { + // TODO: Stop calling PointerTracker.onUpEvent directly. + mainTracker.onUpEvent(x, y, eventTime); + } + } + return; + } + + Log.w(TAG, "Unknown touch panel behavior: pointer count is " + + pointerCount + " (previously " + oldPointerCount + ")"); + } +}