SuddenJumpingTouchEventHandler.java revision c403a46f6d787b79768895272d53d296100677dd
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project 35a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 75a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 95a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 20c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaokaimport android.os.Build; 21faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport android.util.Log; 22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.MotionEvent; 23d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka 2413a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 25c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaokaimport com.android.inputmethod.latin.R; 2613a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka 27c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaokapublic class SuddenJumpingTouchEventHandler { 28c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private static final String TAG = SuddenJumpingTouchEventHandler.class.getSimpleName(); 29faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG; 308eb2e34d5b2def57c9548f88e37e5c9e5a0bea59Amith Yamasani 31c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka public interface ProcessMotionEvent { 32c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka public boolean processMotionEvent(MotionEvent me); 33c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 34c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 35c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private final ProcessMotionEvent mView; 36c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private final boolean mNeedsSuddenJumpingHack; 37c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 380fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** Whether we've started dropping move events because we found a big jump */ 390fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private boolean mDroppingEvents; 40e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka /** 41d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka * Whether multi-touch disambiguation needs to be disabled if a real multi-touch event has 42d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka * occured 430fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani */ 440fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private boolean mDisableDisambiguation; 450fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** The distance threshold at which we start treating the touch session as a multi-touch */ 460fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private int mJumpThresholdSquare = Integer.MAX_VALUE; 47e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka private int mLastX; 48e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka private int mLastY; 493f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani 50c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka public SuddenJumpingTouchEventHandler(Context context, ProcessMotionEvent view) { 51c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mView = view; 52c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka final String[] deviceList = context.getResources().getStringArray( 53c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka R.array.sudden_jumping_touch_event_device_list); 54c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mNeedsSuddenJumpingHack = needsSuddenJumpingHack(Build.DEVICE, deviceList); 55923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 57c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private static boolean needsSuddenJumpingHack(String deviceName, String[] deviceList) { 58c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka for (String device : deviceList) { 59c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka if (device.equalsIgnoreCase(deviceName)) { 60c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka return true; 61c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 62c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 63c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka return false; 64923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 65230cd6f7f27300e2688b5e5a22a5361f446b80e7Amith Yamasani 66050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka public void setKeyboard(Keyboard newKeyboard) { 670fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // One-seventh of the keyboard width seems like a reasonable threshold 688da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int jumpThreshold = newKeyboard.mOccupiedWidth / 7; 69851c3267d4ab21f892b4164783bb4959c88b44ffTadashi G. Takaoka mJumpThresholdSquare = jumpThreshold * jumpThreshold; 700ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa } 710ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa 720fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** 730fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * This function checks to see if we need to handle any sudden jumps in the pointer location 740fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * that could be due to a multi-touch being treated as a move by the firmware or hardware. 750fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * Once a sudden jump is detected, all subsequent move events are discarded 760fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * until an UP is received.<P> 77e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka * When a sudden jump is detected, an UP event is simulated at the last position and when 780fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * the sudden moves subside, a DOWN event is simulated for the second key. 790fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * @param me the motion event 80e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka * @return true if the event was consumed, so that it doesn't continue to be handled by 81ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka * {@link LatinKeyboardBaseView}. 820fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani */ 83c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private boolean handleSuddenJumping(MotionEvent me) { 84c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka if (!mNeedsSuddenJumpingHack) 859a5b592b27158b6fb8b7a89157bb995b182899d8Tadashi G. Takaoka return false; 860fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int action = me.getAction(); 870fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int x = (int) me.getX(); 880fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int y = (int) me.getY(); 890fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani boolean result = false; 900fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 910fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Real multi-touch event? Stop looking for sudden jumps 920fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (me.getPointerCount() > 1) { 930fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDisableDisambiguation = true; 940fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 950fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (mDisableDisambiguation) { 960fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If UP, reset the multi-touch flag 970fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (action == MotionEvent.ACTION_UP) mDisableDisambiguation = false; 980fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani return false; 990fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1000fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 1010fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani switch (action) { 1020fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_DOWN: 1030fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Reset the "session" 1040fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = false; 1050fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDisableDisambiguation = false; 1060fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 1070fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_MOVE: 1080fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Is this a big jump? 1090fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int distanceSquare = (mLastX - x) * (mLastX - x) + (mLastY - y) * (mLastY - y); 110ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka // Check the distance. 111ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka if (distanceSquare > mJumpThresholdSquare) { 1120fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If we're not yet dropping events, start dropping and send an UP event 1130fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (!mDroppingEvents) { 1140fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = true; 1150fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Send an up event 116240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard MotionEvent translated = MotionEvent.obtain( 117240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard me.getEventTime(), me.getEventTime(), 1180fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent.ACTION_UP, 1190fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastX, mLastY, me.getMetaState()); 120c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mView.processMotionEvent(translated); 1210fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani translated.recycle(); 1220fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1230fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani result = true; 1240fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } else if (mDroppingEvents) { 1250fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If moves are small and we're already dropping events, continue dropping 1260fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani result = true; 1270fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1280fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 1290fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_UP: 1300fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (mDroppingEvents) { 1310fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Send a down event first, as we dropped a bunch of sudden jumps and assume that 1320fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // the user is releasing the touch on the second key. 1330fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), 1340fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent.ACTION_DOWN, 1350fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani x, y, me.getMetaState()); 136c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mView.processMotionEvent(translated); 1370fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani translated.recycle(); 1380fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = false; 1390fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Let the up event get processed as well, result = false 1400fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1410fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 1420fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1430fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Track the previous coordinate 1440fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastX = x; 1450fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastY = y; 1460fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani return result; 1470fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1480fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 149358e485b14938fbcb5af5be75aa29f2b73674100Amith Yamasani public boolean onTouchEvent(MotionEvent me) { 150d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka // If there was a sudden jump, return without processing the actual motion event. 151c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka if (handleSuddenJumping(me)) { 152faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 153faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka Log.w(TAG, "onTouchEvent: ignore sudden jump " + me); 154faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka return true; 155faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } 156c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka return mView.processMotionEvent(me); 157bad436e93b49116f9005433845bf53126452a839Amith Yamasani } 158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 159