1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.keyboard.internal; 18 19 import android.util.Log; 20 import android.view.MotionEvent; 21 22 import com.android.inputmethod.keyboard.Key; 23 import com.android.inputmethod.keyboard.KeyDetector; 24 import com.android.inputmethod.keyboard.PointerTracker; 25 import com.android.inputmethod.latin.utils.CoordinateUtils; 26 27 public final class NonDistinctMultitouchHelper { 28 private static final String TAG = NonDistinctMultitouchHelper.class.getSimpleName(); 29 30 private static final int MAIN_POINTER_TRACKER_ID = 0; 31 private int mOldPointerCount = 1; 32 private Key mOldKey; 33 private int[] mLastCoords = CoordinateUtils.newInstance(); 34 35 public void processMotionEvent(final MotionEvent me, final KeyDetector keyDetector) { 36 final int pointerCount = me.getPointerCount(); 37 final int oldPointerCount = mOldPointerCount; 38 mOldPointerCount = pointerCount; 39 // Ignore continuous multi-touch events because we can't trust the coordinates 40 // in multi-touch events. 41 if (pointerCount > 1 && oldPointerCount > 1) { 42 return; 43 } 44 45 // Use only main pointer tracker. 46 final PointerTracker mainTracker = PointerTracker.getPointerTracker( 47 MAIN_POINTER_TRACKER_ID); 48 final int action = me.getActionMasked(); 49 final int index = me.getActionIndex(); 50 final long eventTime = me.getEventTime(); 51 final long downTime = me.getDownTime(); 52 53 // In single-touch. 54 if (oldPointerCount == 1 && pointerCount == 1) { 55 if (me.getPointerId(index) == mainTracker.mPointerId) { 56 mainTracker.processMotionEvent(me, keyDetector); 57 return; 58 } 59 // Inject a copied event. 60 injectMotionEvent(action, me.getX(index), me.getY(index), downTime, eventTime, 61 mainTracker, keyDetector); 62 return; 63 } 64 65 // Single-touch to multi-touch transition. 66 if (oldPointerCount == 1 && pointerCount == 2) { 67 // Send an up event for the last pointer, be cause we can't trust the coordinates of 68 // this multi-touch event. 69 mainTracker.getLastCoordinates(mLastCoords); 70 final int x = CoordinateUtils.x(mLastCoords); 71 final int y = CoordinateUtils.y(mLastCoords); 72 mOldKey = mainTracker.getKeyOn(x, y); 73 // Inject an artifact up event for the old key. 74 injectMotionEvent(MotionEvent.ACTION_UP, x, y, downTime, eventTime, 75 mainTracker, keyDetector); 76 return; 77 } 78 79 // Multi-touch to single-touch transition. 80 if (oldPointerCount == 2 && pointerCount == 1) { 81 // Send a down event for the latest pointer if the key is different from the previous 82 // key. 83 final int x = (int)me.getX(index); 84 final int y = (int)me.getY(index); 85 final Key newKey = mainTracker.getKeyOn(x, y); 86 if (mOldKey != newKey) { 87 // Inject an artifact down event for the new key. 88 // An artifact up event for the new key will usually be injected as a single-touch. 89 injectMotionEvent(MotionEvent.ACTION_DOWN, x, y, downTime, eventTime, 90 mainTracker, keyDetector); 91 if (action == MotionEvent.ACTION_UP) { 92 // Inject an artifact up event for the new key also. 93 injectMotionEvent(MotionEvent.ACTION_UP, x, y, downTime, eventTime, 94 mainTracker, keyDetector); 95 } 96 } 97 return; 98 } 99 100 Log.w(TAG, "Unknown touch panel behavior: pointer count is " 101 + pointerCount + " (previously " + oldPointerCount + ")"); 102 } 103 104 private static void injectMotionEvent(final int action, final float x, final float y, 105 final long downTime, final long eventTime, final PointerTracker tracker, 106 final KeyDetector keyDetector) { 107 final MotionEvent me = MotionEvent.obtain( 108 downTime, eventTime, action, x, y, 0 /* metaState */); 109 try { 110 tracker.processMotionEvent(me, keyDetector); 111 } finally { 112 me.recycle(); 113 } 114 } 115 } 116