SuddenJumpingTouchEventHandler.java revision 9879f65651a748e4c0a45715eb7d5663652f1127
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 1799906b3fc2dcb447aafdd43dda0c4551513b293eTadashi G. Takaokapackage com.android.inputmethod.keyboard.internal; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 20faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport android.util.Log; 21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.MotionEvent; 22d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka 2399906b3fc2dcb447aafdd43dda0c4551513b293eTadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 2499906b3fc2dcb447aafdd43dda0c4551513b293eTadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView; 2513a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 26c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaokaimport com.android.inputmethod.latin.R; 279879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils; 289bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 296b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 3013a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka 31c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaokapublic class SuddenJumpingTouchEventHandler { 32c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private static final String TAG = SuddenJumpingTouchEventHandler.class.getSimpleName(); 33faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG; 348eb2e34d5b2def57c9548f88e37e5c9e5a0bea59Amith Yamasani 35c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka public interface ProcessMotionEvent { 36c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka public boolean processMotionEvent(MotionEvent me); 37c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 38c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 39c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private final ProcessMotionEvent mView; 40c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private final boolean mNeedsSuddenJumpingHack; 41c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 420fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** Whether we've started dropping move events because we found a big jump */ 430fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private boolean mDroppingEvents; 44e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka /** 45d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka * Whether multi-touch disambiguation needs to be disabled if a real multi-touch event has 46d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka * occured 470fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani */ 480fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private boolean mDisableDisambiguation; 490fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** The distance threshold at which we start treating the touch session as a multi-touch */ 500fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private int mJumpThresholdSquare = Integer.MAX_VALUE; 51e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka private int mLastX; 52e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka private int mLastY; 533f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani 54c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka public SuddenJumpingTouchEventHandler(Context context, ProcessMotionEvent view) { 55c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mView = view; 569879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka mNeedsSuddenJumpingHack = Boolean.parseBoolean(ResourceUtils.getDeviceOverrideValue( 57624f1bab39357eb716dfc7ec6b723da3f926f5a2Tadashi G. Takaoka context.getResources(), R.array.sudden_jumping_touch_event_device_list, "false")); 58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 59230cd6f7f27300e2688b5e5a22a5361f446b80e7Amith Yamasani 60050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka public void setKeyboard(Keyboard newKeyboard) { 610fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // One-seventh of the keyboard width seems like a reasonable threshold 628da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int jumpThreshold = newKeyboard.mOccupiedWidth / 7; 63851c3267d4ab21f892b4164783bb4959c88b44ffTadashi G. Takaoka mJumpThresholdSquare = jumpThreshold * jumpThreshold; 640ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa } 650ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa 660fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** 670fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * This function checks to see if we need to handle any sudden jumps in the pointer location 680fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * that could be due to a multi-touch being treated as a move by the firmware or hardware. 690fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * Once a sudden jump is detected, all subsequent move events are discarded 700fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * until an UP is received.<P> 71e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka * When a sudden jump is detected, an UP event is simulated at the last position and when 720fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * the sudden moves subside, a DOWN event is simulated for the second key. 730fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * @param me the motion event 74e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka * @return true if the event was consumed, so that it doesn't continue to be handled by 75c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka * {@link MainKeyboardView}. 760fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani */ 77c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka private boolean handleSuddenJumping(MotionEvent me) { 78c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka if (!mNeedsSuddenJumpingHack) 799a5b592b27158b6fb8b7a89157bb995b182899d8Tadashi G. Takaoka return false; 800fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int action = me.getAction(); 810fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int x = (int) me.getX(); 820fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int y = (int) me.getY(); 830fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani boolean result = false; 840fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 850fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Real multi-touch event? Stop looking for sudden jumps 860fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (me.getPointerCount() > 1) { 870fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDisableDisambiguation = true; 880fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 890fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (mDisableDisambiguation) { 900fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If UP, reset the multi-touch flag 910fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (action == MotionEvent.ACTION_UP) mDisableDisambiguation = false; 920fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani return false; 930fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 940fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 950fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani switch (action) { 960fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_DOWN: 970fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Reset the "session" 980fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = false; 990fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDisableDisambiguation = false; 1000fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 1010fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_MOVE: 1020fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Is this a big jump? 1030fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int distanceSquare = (mLastX - x) * (mLastX - x) + (mLastY - y) * (mLastY - y); 104ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka // Check the distance. 105ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka if (distanceSquare > mJumpThresholdSquare) { 1060fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If we're not yet dropping events, start dropping and send an UP event 1070fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (!mDroppingEvents) { 1080fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = true; 1090fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Send an up event 110240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard MotionEvent translated = MotionEvent.obtain( 111240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard me.getEventTime(), me.getEventTime(), 1120fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent.ACTION_UP, 1130fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastX, mLastY, me.getMetaState()); 114c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mView.processMotionEvent(translated); 1150fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani translated.recycle(); 1160fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1170fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani result = true; 1180fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } else if (mDroppingEvents) { 1190fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If moves are small and we're already dropping events, continue dropping 1200fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani result = true; 1210fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1220fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 1230fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_UP: 1240fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (mDroppingEvents) { 1250fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Send a down event first, as we dropped a bunch of sudden jumps and assume that 1260fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // the user is releasing the touch on the second key. 1270fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), 1280fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent.ACTION_DOWN, 1290fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani x, y, me.getMetaState()); 130c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mView.processMotionEvent(translated); 1310fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani translated.recycle(); 1320fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = false; 1330fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Let the up event get processed as well, result = false 1340fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1350fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 1360fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1370fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Track the previous coordinate 1380fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastX = x; 1390fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastY = y; 1400fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani return result; 1410fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1420fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 143358e485b14938fbcb5af5be75aa29f2b73674100Amith Yamasani public boolean onTouchEvent(MotionEvent me) { 144d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka // If there was a sudden jump, return without processing the actual motion event. 145c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka if (handleSuddenJumping(me)) { 146faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 147faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka Log.w(TAG, "onTouchEvent: ignore sudden jump " + me); 1489bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1499bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.suddenJumpingTouchEventHandler_onTouchEvent(me); 1509bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 151faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka return true; 152faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } 153c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka return mView.processMotionEvent(me); 154bad436e93b49116f9005433845bf53126452a839Amith Yamasani } 155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 156