From b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690 Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Wed, 31 Jul 2013 18:13:42 +0900
Subject: [PATCH] Move non-distinct multitouch support to a separate class

Move code that support non-distinct multitouch screen device to the
NonDistinchMultitouchHelper class.

Change-Id: I2e44f782b83dbcd095ee8e51c36b0766da0cd457
---
 .../keyboard/MainKeyboardView.java            | 80 ++++-------------
 .../inputmethod/keyboard/PointerTracker.java  |  9 +-
 .../internal/NonDistinctMultitouchHelper.java | 90 +++++++++++++++++++
 3 files changed, 112 insertions(+), 67 deletions(-)
 create mode 100644 java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java

diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 98eed264f2..7ceff388e2 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 7079b4d024..bbaf96982f 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 0000000000..53fff69864
--- /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 + ")");
+    }
+}
-- 
GitLab