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.common.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 processMotionEvent(final MotionEvent me, final KeyDetector keyDetector)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 injectMotionEvent(final int action, final float x, final float y, final long downTime, final long eventTime, final PointerTracker tracker, final KeyDetector keyDetector)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