From c8b9afe0378e3f33c3f83271bd1df9678a70c2a2 Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Mon, 6 Sep 2010 14:26:46 +0900
Subject: [PATCH] Support multi-touch only when device has distinct multi-touch
 panel

Bug: 2973373
Change-Id: I9871c09ec8c1c2aa945d97392e61ee1ec585baef
---
 .../inputmethod/latin/KeyboardSwitcher.java   |  4 ++
 .../android/inputmethod/latin/LatinIME.java   | 10 ++--
 .../latin/LatinKeyboardBaseView.java          | 51 ++++++++++++++++++-
 .../inputmethod/latin/PointerTracker.java     | 34 +++++++++++--
 4 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
index 2919e9b566..3fb74b238a 100644
--- a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
@@ -365,6 +365,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         }
     }
 
+    public boolean hasDistinctMultitouch() {
+        return mInputView != null && mInputView.hasDistinctMultitouch();
+    }
+
     /**
      * Updates state machine to figure out when to automatically switch back to alpha mode.
      * Returns true if the keyboard needs to switch back 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ea8c939345..2cff232a62 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1135,7 +1135,9 @@ public class LatinIME extends InputMethodService
                 LatinImeLogger.logOnDelete();
                 break;
             case Keyboard.KEYCODE_SHIFT:
-                // Shift key is handled in onPress().
+                // Shift key is handled in onPress() when device has distinct multi-touch panel.
+                if (!mKeyboardSwitcher.hasDistinctMultitouch())
+                    handleShift();
                 break;
             case Keyboard.KEYCODE_CANCEL:
                 if (!isShowingOptionDialog()) {
@@ -1935,7 +1937,7 @@ public class LatinIME extends InputMethodService
             List<CharSequence> suggestions = mWordToSuggestions.get(selectedWord);
             // If the first letter of touching is capitalized, make all the suggestions
             // start with a capital letter.
-            if (Character.isUpperCase((char) touching.word.charAt(0))) {
+            if (Character.isUpperCase(touching.word.charAt(0))) {
                 for (int i = 0; i < suggestions.size(); i++) {
                     String origSugg = (String) suggestions.get(i);
                     String capsSugg = origSugg.toUpperCase().charAt(0)
@@ -2196,7 +2198,7 @@ public class LatinIME extends InputMethodService
     public void onPress(int primaryCode) {
         vibrate();
         playKeyClick(primaryCode);
-        if (primaryCode == Keyboard.KEYCODE_SHIFT) {
+        if (mKeyboardSwitcher.hasDistinctMultitouch() && primaryCode == Keyboard.KEYCODE_SHIFT) {
             mShiftKeyState.onPress();
             handleShift();
         } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
@@ -2210,7 +2212,7 @@ public class LatinIME extends InputMethodService
         // Reset any drag flags in the keyboard
         ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).keyReleased();
         //vibrate();
-        if (primaryCode == Keyboard.KEYCODE_SHIFT) {
+        if (mKeyboardSwitcher.hasDistinctMultitouch() && primaryCode == Keyboard.KEYCODE_SHIFT) {
             if (mShiftKeyState.isMomentary())
                 resetShift();
             mShiftKeyState.onRelease();
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
index c449b36e7c..51bdc2c0cc 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.latin;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -204,6 +205,8 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
     private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>();
     private final PointerQueue mPointerQueue = new PointerQueue();
     private final float mDebounceHysteresis;
+    private final boolean mHasDistinctMultitouch;
+    private int mOldPointerCount = 1;
 
     protected KeyDetector mKeyDetector = new ProximityKeyDetector();
 
@@ -508,6 +511,9 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         final boolean ignoreMultitouch = true;
         mGestureDetector = new GestureDetector(getContext(), listener, null, ignoreMultitouch);
         mGestureDetector.setIsLongpressEnabled(false);
+
+        mHasDistinctMultitouch = context.getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
     }
 
     public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
@@ -563,6 +569,14 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         return mKeyboard;
     }
 
+    /**
+     * Return whether the device has distinct multi-touch panel.
+     * @return true if the device has distinct multi-touch panel.
+     */
+    public boolean hasDistinctMultitouch() {
+        return mHasDistinctMultitouch;
+    }
+
     /**
      * Sets the state of the shift key of the keyboard, if any.
      * @param shifted whether or not to enable the state of the shift key
@@ -1090,7 +1104,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         // Create pointer trackers until we can get 'id+1'-th tracker, if needed.
         for (int i = pointers.size(); i <= id; i++) {
             final PointerTracker tracker =
-                new PointerTracker(i, mHandler, mKeyDetector, this);
+                new PointerTracker(i, mHandler, mKeyDetector, this, mHasDistinctMultitouch);
             if (keys != null)
                 tracker.setKeyboard(keys, mDebounceHysteresis);
             if (listener != null)
@@ -1107,6 +1121,13 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         final int action = me.getActionMasked();
         final long eventTime = me.getEventTime();
 
+        // 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 (!mHasDistinctMultitouch && pointerCount > 1 && mOldPointerCount > 1) {
+            return true;
+        }
+
         // Track the last few movements to look for spurious swipes.
         mSwipeTracker.addMovement(me);
 
@@ -1138,6 +1159,34 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
             // 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 (!mHasDistinctMultitouch) {
+            // Use only main (id=0) pointer tracker.
+            PointerTracker tracker = getPointerTracker(0);
+            int index = me.getActionIndex();
+            int x = (int)me.getX(index);
+            int y = (int)me.getY(index);
+            int oldPointerCount = mOldPointerCount;
+            if (pointerCount == 1 && oldPointerCount == 2) {
+                // Multi-touch to single touch transition.
+                // Send a down event for the latest pointer.
+                tracker.onDownEvent(x, y, eventTime);
+            } else if (pointerCount == 2 && oldPointerCount == 1) {
+                // Single-touch to multi-touch transition.
+                // Send an up event for the last pointer.
+                tracker.onUpEvent(tracker.getLastX(), tracker.getLastY(), eventTime);
+            } else if (pointerCount == 1 && oldPointerCount == 1) {
+                tracker.onTouchEvent(action, x, y, eventTime);
+            } else {
+                Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount
+                        + " (old " + oldPointerCount + ")");
+            }
+            mOldPointerCount = pointerCount;
+            return true;
+        }
+
         if (action == MotionEvent.ACTION_MOVE) {
             for (int index = 0; index < pointerCount; index++) {
                 int x = (int)me.getX(index);
diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/latin/PointerTracker.java
index 2685e87c6d..1f60056211 100644
--- a/java/src/com/android/inputmethod/latin/PointerTracker.java
+++ b/java/src/com/android/inputmethod/latin/PointerTracker.java
@@ -22,12 +22,13 @@ import com.android.inputmethod.latin.LatinKeyboardBaseView.UIHandler;
 import android.inputmethodservice.Keyboard;
 import android.inputmethodservice.Keyboard.Key;
 import android.util.Log;
+import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
 public class PointerTracker {
     private static final String TAG = "PointerTracker";
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_MOVE = DEBUG && true;
+    private static final boolean DEBUG_MOVE = false;
 
     public interface UIProxy {
         public void invalidateKey(Key key);
@@ -51,6 +52,7 @@ public class PointerTracker {
     private final UIHandler mHandler;
     private final KeyDetector mKeyDetector;
     private OnKeyboardActionListener mListener;
+    private final boolean mHasDistinctMultitouch;
 
     private Key[] mKeys;
     private int mKeyDebounceThresholdSquared = -1;
@@ -85,13 +87,15 @@ public class PointerTracker {
     // pressed key
     private int mPreviousKey = NOT_A_KEY;
 
-    public PointerTracker(int id, UIHandler handler, KeyDetector keyDetector, UIProxy proxy) {
+    public PointerTracker(int id, UIHandler handler, KeyDetector keyDetector, UIProxy proxy,
+            boolean hasDistinctMultitouch) {
         if (proxy == null || handler == null || keyDetector == null)
             throw new NullPointerException();
         mPointerId = id;
         mProxy = proxy;
         mHandler = handler;
         mKeyDetector = keyDetector;
+        mHasDistinctMultitouch = hasDistinctMultitouch;
         resetMultiTap();
     }
 
@@ -146,6 +150,25 @@ public class PointerTracker {
         mKeyAlreadyProcessed = true;
     }
 
+    public void onTouchEvent(int action, int x, int y, long eventTime) {
+        switch (action) {
+        case MotionEvent.ACTION_MOVE:
+            onMoveEvent(x, y, eventTime);
+            break;
+        case MotionEvent.ACTION_DOWN:
+        case MotionEvent.ACTION_POINTER_DOWN:
+            onDownEvent(x, y, eventTime);
+            break;
+        case MotionEvent.ACTION_UP:
+        case MotionEvent.ACTION_POINTER_UP:
+            onUpEvent(x, y, eventTime);
+            break;
+        case MotionEvent.ACTION_CANCEL:
+            onCancelEvent(x, y, eventTime);
+            break;
+        }
+    }
+
     public void onDownEvent(int x, int y, long eventTime) {
         int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null);
         mCurrentKey = keyIndex;
@@ -242,7 +265,7 @@ public class PointerTracker {
         showKeyPreviewAndUpdateKey(NOT_A_KEY);
         // If we're not on a repeating key (which sends on a DOWN event)
         if (!wasInKeyRepeat) {
-            detectAndSendKey(mCurrentKey, (int)x, (int)y, eventTime);
+            detectAndSendKey(mCurrentKey, x, y, eventTime);
         }
         if (isValidKeyIndex(keyIndex))
             mProxy.invalidateKey(mKeys[keyIndex]);
@@ -355,7 +378,10 @@ public class PointerTracker {
 
     private void showKeyPreviewAndUpdateKey(int keyIndex) {
         updateKey(keyIndex);
-        if (!isModifier())
+        // The modifier key, such as shift key, should not be shown as preview when multi-touch is
+        // supported. On thge other hand, if multi-touch is not supported, the modifier key should
+        // be shown as preview.
+        if (!isModifier() || !mHasDistinctMultitouch)
             mProxy.showPreview(keyIndex, this);
     }
 
-- 
GitLab