PointerTracker.java revision 8353e751cae4a26d186fb645e9d3d40e1bc5d14b
16a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka/* 28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 36a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 46a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); you may not 56a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * use this file except in compliance with the License. You may obtain a copy of 66a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * the License at 76a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 86a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 96a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 106a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 116a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 126a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 136a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * License for the specific language governing permissions and limitations under 146a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * the License. 156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka */ 166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 195509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport android.content.res.TypedArray; 20e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaokaimport android.os.SystemClock; 21c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport android.util.Log; 228ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaokaimport android.view.MotionEvent; 23c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 24918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 25f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStroke; 2680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams; 27c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints; 2872934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 295f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils; 30240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaokaimport com.android.inputmethod.latin.Constants; 31547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaokaimport com.android.inputmethod.latin.CoordinateUtils; 32f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 33faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 345509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport com.android.inputmethod.latin.R; 359bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 366b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 376a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 385c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 39dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 40a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class PointerTracker implements PointerTrackerQueue.Element { 41dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 42dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 43dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 44dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 45b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG || DEBUG_EVENT; 4640a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 470657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka /** True if {@link PointerTracker}s should handle gesture events. */ 480657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka private static boolean sShouldHandleGesture = false; 498335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sMainDictionaryAvailable = false; 508335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByInputField = false; 518335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByUser = false; 52918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 53f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public interface KeyEventHandler { 54f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 55f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyDetector object that is used for this PointerTracker. 56f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyDetector object that is used for this PointerTracker 57f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 58f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyDetector getKeyDetector(); 59f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 60f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 61f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyboardActionListener object that is used to register key code and so on. 62f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyboardActionListner for this PointerTracker 63f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 64f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener(); 65f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 66f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 67f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get DrawingProxy object that is used for this PointerTracker. 68f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the DrawingProxy object that is used for this PointerTracker 69f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 70f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy(); 71f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 72f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 73f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get TimerProxy object that handles key repeat and long press timer event for this 74f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * PointerTracker. 75f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the TimerProxy object that handles key repeat and long press timer event. 76f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 77f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public TimerProxy getTimerProxy(); 78f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 79f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 80fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang public interface DrawingProxy { 816a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public void invalidateKey(Key key); 82e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public void showKeyPreview(PointerTracker tracker); 83d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void dismissKeyPreview(PointerTracker tracker); 84547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void showSlidingKeyInputPreview(PointerTracker tracker); 8508d8a676c28f30a722629cb4713177064f6422e2Tadashi G. Takaoka public void dismissSlidingKeyInputPreview(); 86f0e83046f022b5594f98aef07fbda7f2f837f262Tadashi G. Takaoka public void showGesturePreviewTrail(PointerTracker tracker, boolean isOldestTracker); 876a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 886a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 892321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public interface TimerProxy { 90d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey); 9173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState(); 92a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker); 93a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker); 94a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code); 9598b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer(); 960ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer(); 97beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer(); 980ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout(); 992321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelKeyTimers(); 10072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(PointerTracker tracker); 1012db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers(); 10229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 10329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static class Adapter implements TimerProxy { 10429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 105d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey) {} 10693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 10773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { return false; } 10893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 109a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker) {} 11029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 111a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker) {} 112a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 113a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code) {} 11429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 11529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelLongPressTimer() {} 11629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 1170ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer() {} 1180ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 119beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer() {} 120beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 1210ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout() { return false; } 1220ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 12329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelKeyTimers() {} 12472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 12572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(PointerTracker tracker) {} 12672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 1272db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers() {} 12829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 1292321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka } 1302321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka 131a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka static final class PointerTrackerParams { 1325509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final boolean mSlidingKeyInputEnabled; 1335509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final int mTouchNoiseThresholdTime; 134b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public final int mTouchNoiseThresholdDistance; 1353623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public final int mSuppressKeyPreviewAfterBatchInputDuration; 1365509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1375509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); 1385509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1395509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private PointerTrackerParams() { 1405509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = false; 1415509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = 0; 142b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = 0; 1433623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 0; 1445509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1455509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 14680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) { 1475509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean( 1485509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_slidingKeyInputEnable, false); 1495509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( 1505509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); 151b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( 1525509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); 1533623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt( 1543623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0); 1555509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1565509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1575509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 158160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka // Parameters for pointer handling. 1595509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private static PointerTrackerParams sParams; 16080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private static GestureStrokeParams sGestureStrokeParams; 161d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka private static boolean sNeedsPhantomSuddenMoveEventHack; 162b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move this threshold to resource. 163b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // TODO: Device specific parameter would be better for device specific hack? 164b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth 165b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // This hack might be device specific. 166b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final boolean sNeedsProximateBogusDownMoveUpEventHack = true; 1675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1685f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); 16993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue(); 1705c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1715c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 1726a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1730efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 1740efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 175a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 176dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private KeyboardActionListener mListener = EMPTY_LISTENER; 177baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1785a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 179b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mPhantonSuddenMoveThreshold; 180b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); 1816a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1826c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private boolean mIsDetectingGesture = false; // per PointerTracker. 1836c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static boolean sInGesture = false; 1846c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static long sGestureFirstDownTime; 1853623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private static TimeRecorder sTimeRecorder; 1866c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static final InputPointers sAggregratedPointers = new InputPointers( 1876c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka GestureStroke.DEFAULT_CAPACITY); 18858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers 18958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers 1909580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 191b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static final class BogusMoveEventDetector { 192b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move these thresholds to resource. 193d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // These thresholds' unit is a diagonal length of a key. 194d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f; 195d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f; 196b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 197b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mAccumulatedDistanceThreshold; 198b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mRadiusThreshold; 199b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 200b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Accumulated distance from actual and artificial down keys. 201b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int mAccumulatedDistanceFromDownKey; 202b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownX; 203b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownY; 204b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 205d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public void setKeyboardGeometry(final int keyWidth, final int keyHeight) { 206d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight); 207b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceThreshold = (int)( 208d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); 209d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD); 210b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 211b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 212b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onActualDownEvent(final int x, final int y) { 213b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownX = x; 214b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownY = y; 215b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 216b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 217b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onDownKey() { 218b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey = 0; 219b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 220b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 221b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onMoveKey(final int distance) { 222b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey += distance; 223b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 224b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 225d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public boolean hasTraveledLongDistance(final int x, final int y) { 226d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dx = Math.abs(x - mActualDownX); 227d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dy = Math.abs(y - mActualDownY); 228d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // A bogus move event should be a horizontal movement. A vertical movement might be 229d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // a sloppy typing and should be ignored. 230d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; 231b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 232b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 233b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int getDistanceFromDownEvent(final int x, final int y) { 234b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistance(x, y, mActualDownX, mActualDownY); 235b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 236b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 237b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isCloseToActualDownEvent(final int x, final int y) { 238b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistanceFromDownEvent(x, y) < mRadiusThreshold; 239b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 240b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 241b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2423623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka static final class TimeRecorder { 2433623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mSuppressKeyPreviewAfterBatchInputDuration; 2443623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mStaticTimeThresholdAfterFastTyping; // msec 2453623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastTypingTime; 2463623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastLetterTypingTime; 2473623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastBatchInputTime; 2483623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2493623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public TimeRecorder(final PointerTrackerParams pointerTrackerParams, 2503623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final GestureStrokeParams gestureStrokeParams) { 2513623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 2523623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka pointerTrackerParams.mSuppressKeyPreviewAfterBatchInputDuration; 2533623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = 2543623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka gestureStrokeParams.mStaticTimeThresholdAfterFastTyping; 2553623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2563623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 257b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isInFastTyping(final long eventTime) { 258b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; 259b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; 260b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 261b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2627a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka private boolean wasLastInputTyping() { 2637a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return mLastTypingTime >= mLastBatchInputTime; 2643623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2653623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2663623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onCodeInput(final int code, final long eventTime) { 2677a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // Record the letter typing time when 2687a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 1. Letter keys are typed successively without any batch input in between. 2697a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 2. A letter key is typed within the threshold time since the last any key typing. 2707a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 3. A non-letter key is typed within the threshold time since the last letter key 2717a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // typing. 2727a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (Character.isLetter(code)) { 2737a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (wasLastInputTyping() 2747a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) { 2757a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2763623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2773623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } else { 2783623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) { 2793623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // This non-letter typing should be treated as a part of fast typing. 2807a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2813623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2823623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2837a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastTypingTime = eventTime; 2843623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2853623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2863623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onEndBatchInput(final long eventTime) { 2877a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastBatchInputTime = eventTime; 2883623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2893623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2903623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public long getLastLetterTypingTime() { 2913623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return mLastLetterTypingTime; 2923623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2933623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2943623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 2957a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return !wasLastInputTyping() 2963623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration; 2973623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2983623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2993623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 3008a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 3018a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 302547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka private int[] mDownCoordinates = CoordinateUtils.newInstance(); 3038a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 3048a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 305e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The current key where this pointer is. 306e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mCurrentKey = null; 307e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The position where the current key was recognized for the first time. 3088a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 3098a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 3108a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3118a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 3128a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 3138a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 3146a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3151a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 3161a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 3171a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 318b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka // true if this pointer is no longer tracking touch event. 319b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka private boolean mIsTrackingCanceled; 320c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 32135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang // the more keys panel currently being shown. equals null if no panel is active. 32235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private MoreKeysPanel mMoreKeysPanel; 3239ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 324f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input. 3255c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 326f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input from a modifier key, 327f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // so that further modifier keys should be ignored. 328f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka boolean mIsInSlidingKeyInputFromModifier; 329cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 330f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if a sliding key input is allowed. 33167a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 33267a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 333dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Empty {@link KeyboardActionListener} 334e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka private static final KeyboardActionListener EMPTY_LISTENER = 335e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka new KeyboardActionListener.Adapter(); 3366e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka 337c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; 338f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 33993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka public static void init(final boolean needsPhantomSuddenMoveEventHack) { 340d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack; 3415509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = PointerTrackerParams.DEFAULT; 34280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = GestureStrokeParams.DEFAULT; 3433623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 344160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 34593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3465509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static void setParameters(final TypedArray mainKeyboardViewAttr) { 3475509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = new PointerTrackerParams(mainKeyboardViewAttr); 34880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr); 3493623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 3506a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3516a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3528335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static void updateGestureHandlingMode() { 3538335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sShouldHandleGesture = sMainDictionaryAvailable 3548335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByInputField 3558335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByUser 3568335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); 3578335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 3588335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 3598335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 360694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 3618335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sMainDictionaryAvailable = mainDictionaryAvailable; 3628335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 3638335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 3648335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 365694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 3668335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; 3678335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 368918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka } 369918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 370694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, final KeyEventHandler handler) { 371b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka final ArrayList<PointerTracker> trackers = sTrackers; 3725c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3735c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 3745c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 3755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 3765c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 3775c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3785c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3795c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 3805c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3825c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 38393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.isAnyInSlidingKeyInput(); 3845c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3855c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 386694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyboardActionListener(final KeyboardActionListener listener) { 387afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 388afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 389afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 3905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 3915c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3925c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3935c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 394694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyDetector(final KeyDetector keyDetector) { 395afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 396afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 397afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 3985c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 3995c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 4005c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 4015c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 402918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 4038335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput(); 4048335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 4055c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4065c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 407dde36ef34329164cf8b8a3985c578dab0343b3ebTadashi G. Takaoka public static void setReleasedKeyGraphicsToAllKeys() { 408afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 409afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 410afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 411e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.mCurrentKey); 4125c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4135c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4145c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 415ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang public static void dismissAllMoreKeysPanels() { 416ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final int trackersSize = sTrackers.size(); 417ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang for (int i = 0; i < trackersSize; ++i) { 418ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final PointerTracker tracker = sTrackers.get(i); 419ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (tracker.isShowingMoreKeysPanel()) { 420ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang tracker.mMoreKeysPanel.dismissMoreKeysPanel(); 421ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang tracker.mMoreKeysPanel = null; 422ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 423ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 424ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 425ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 426694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private PointerTracker(final int id, final KeyEventHandler handler) { 427694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (handler == null) { 4285c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 429694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 4305c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 43180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints( 43280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka id, sGestureStrokeParams); 4335c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 4345c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 4355c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 4365c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 4376a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4386a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 4391a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 440694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key) { 4416c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 442eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return false; 443eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 444f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 445e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 44658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId, 44758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka KeyDetector.printableCode(key), 44858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka ignoreModifierKey ? " ignoreModifier" : "", 44958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "" : " disabled")); 450e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 45193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (ignoreModifierKey) { 452996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 45393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 454e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 4552a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onPressKey(key.mCode); 456690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 457690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 458d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 459690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 460690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 461690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 462dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 463dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 464690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 465690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 466694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, 4673623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final int y, final long eventTime) { 468f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 4696bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 47029d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int code = altersCode ? key.getAltCode() : primaryCode; 4712013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (DEBUG_LISTENER) { 472240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final String output = code == Constants.CODE_OUTPUT_TEXT 473240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka ? key.getOutputText() : Constants.printableCode(code); 47458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y, 47558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka output, ignoreModifierKey ? " ignoreModifier" : "", 47658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled")); 4772013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4789bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4799bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, 4809bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge altersCode, code); 4819bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 482e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 483996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 484e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 4856bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 4866bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.isEnabled() || altersCode) { 4873623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onCodeInput(code, eventTime); 488240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (code == Constants.CODE_OUTPUT_TEXT) { 48929d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka mListener.onTextInput(key.getOutputText()); 490240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (code != Constants.CODE_UNSPECIFIED) { 491ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mListener.onCodeInput(code, x, y); 4922013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 49393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 494dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 495dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 496f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may be in shifted state and the 497690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 498694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnRelease(final Key key, final int primaryCode, 499694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final boolean withSliding) { 5006c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 501eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 502eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 503f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 504e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 50558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, 506240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka Constants.printableCode(primaryCode), 50758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "", 50858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "": " disabled")); 509e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 5109bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 5119bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, 5129bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ignoreModifierKey); 5139bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 514e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 515996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 516e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 51793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (key.isEnabled()) { 5182a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onReleaseKey(primaryCode, withSliding); 51993246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 520dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 521dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 5228aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 523694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_LISTENER) { 52458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelInput", mPointerId)); 525694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 5269bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 5279bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCancelInput(); 5289bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 5298aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 530dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 531dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 532694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setKeyDetectorInner(final KeyDetector keyDetector) { 53358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 53458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (keyDetector == mKeyDetector && keyboard == mKeyboard) { 53558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return; 53658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 537a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 5385a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 539d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyWidth = mKeyboard.mMostCommonKeyWidth; 540d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyHeight = mKeyboard.mMostCommonKeyHeight; 541b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); 5428a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); 5438a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (newKey != mCurrentKey) { 5448a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (mDrawingProxy != null) { 5458a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 5468a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 54744972bcdb6f6dd0e4f02a26f31c7effaf0525403Tadashi G. Takaoka // Keep {@link #mCurrentKey} that comes from previous keyboard. 5488a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 549b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); 550d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mBogusMoveEventDetector.setKeyboardGeometry(keyWidth, keyHeight); 5515a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 5525a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 5530cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 554cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 555cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 556cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 557cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 558547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public boolean isInSlidingKeyInputFromModifier() { 559547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka return mIsInSlidingKeyInputFromModifier; 560547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka } 561547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka 562e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKey() { 563e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey; 564dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 565dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 5660cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 5672aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 568e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey != null && mCurrentKey.isModifier(); 5692aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 5702aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 571694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public Key getKeyOn(final int x, final int y) { 572723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 5732aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 5742aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 575694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setReleasedKeyGraphics(final Key key) { 576d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 5776bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 578faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 579faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 580faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 5816bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, update the key release graphics just in case. 582faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(key); 583faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 584faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 585faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 586faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 587faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(shiftKey); 5882013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5892013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 590faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 5912013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 592faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.altCodeWhileTyping()) { 59329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 594faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 595faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 596faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(altKey); 597faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 598faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 59929d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 600faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(k); 6012013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6022013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6036a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6046a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6056a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 60629d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 60729d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!sShouldHandleGesture) return false; 6083623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime); 60929d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka } 61029d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka 61129d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void setPressedKeyGraphics(final Key key, final long eventTime) { 6126bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 6136bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka return; 6146bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 6156bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka 6166bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 6176bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 6186bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; 6196bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (!needsToUpdateGraphics) { 620faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 621faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 622faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 62329d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!key.noKeyPreview() && !sInGesture && !needsToSuppressKeyPreviewPopup(eventTime)) { 624faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.showKeyPreview(this); 625faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 626faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(key); 627faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 628faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 629faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 630faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 631faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(shiftKey); 6322013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6332013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 634faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 6352013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 63673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) { 63729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 638faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 639faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 640faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(altKey); 641faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 642faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 64329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 644faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(k); 6452013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6462013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 647d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 648c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 649c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 650694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updateReleaseKeyGraphics(final Key key) { 651faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onReleased(); 652faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 653faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 654faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 655694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updatePressKeyGraphics(final Key key) { 656faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onPressed(); 657faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 658faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 659faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 660c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { 661c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka return mGestureStrokeWithPreviewPoints; 6622f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 6632f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang 664547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void getLastCoordinates(final int[] outCoords) { 665547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.set(outCoords, mLastX, mLastY); 6668a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6678a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 6688a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 6698a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 6708a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6718a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 672547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void getDownCoordinates(final int[] outCoords) { 673547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.copy(outCoords, mDownCoordinates); 674547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka } 675547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka 676694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onDownKey(final int x, final int y, final long eventTime) { 6778a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 678547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.set(mDownCoordinates, x, y); 679b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onDownKey(); 6808a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 6818a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6828a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 683b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static int getDistance(final int x1, final int y1, final int x2, final int y2) { 684b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return (int)Math.hypot(x1 - x2, y1 - y2); 685b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 686b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 687694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKeyInternal(final int x, final int y) { 688b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onMoveKey(getDistance(x, y, mLastX, mLastY)); 6898a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 6908a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 691723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 6928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6938a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 694694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKey(final int x, final int y) { 6958a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 6968a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6978a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 698694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveToNewKey(final Key newKey, final int x, final int y) { 699e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mCurrentKey = newKey; 7008a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 7018a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 702e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return newKey; 7038a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7048a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 7056c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static int getActivePointerTrackerCount() { 70693b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.size(); 7076c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7086c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 70913ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka private static boolean isOldestTrackerInQueue(final PointerTracker tracker) { 71093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.getOldestElement() == tracker; 71113ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka } 71213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka 7131645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka private void mayStartBatchInput(final Key key) { 714c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { 7159c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka return; 7169c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka } 7171645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka if (key == null || !Character.isLetter(key.mCode)) { 7181645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka return; 7191645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka } 7209c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka if (DEBUG_LISTENER) { 72158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); 7229580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7239c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka sInGesture = true; 72458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka synchronized (sAggregratedPointers) { 72558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sAggregratedPointers.reset(); 72658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionPointSize = 0; 72758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionTime = 0; 72858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mListener.onStartBatchInput(); 729ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang dismissAllMoreKeysPanels(); 73058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 731ad181915f78235bc09e88c85ed9df669801b8442Tadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 73213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this)); 7336c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7346c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 73572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void updateBatchInputByTimer(final long eventTime) { 73672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 73772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.duplicateLastPointWith(gestureTime); 73872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka updateBatchInput(eventTime); 73972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 74072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 741157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka private void mayUpdateBatchInput(final long eventTime, final Key key) { 742157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (key != null) { 74372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka updateBatchInput(eventTime); 74472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 7456f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka if (mIsTrackingCanceled) { 7466f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka return; 7476f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka } 74872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this)); 74972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 75072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 75172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private void updateBatchInput(final long eventTime) { 75272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka synchronized (sAggregratedPointers) { 75372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final GestureStroke stroke = mGestureStrokeWithPreviewPoints; 75472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka stroke.appendIncrementalBatchPoints(sAggregratedPointers); 75572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int size = sAggregratedPointers.getPointerSize(); 75672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (size > sLastRecognitionPointSize 75772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) { 75872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka sLastRecognitionPointSize = size; 75972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka sLastRecognitionTime = eventTime; 76072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (DEBUG_LISTENER) { 76172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, 76272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka size)); 7636c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 76472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mTimerProxy.startUpdateBatchInputTimer(this); 76572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mListener.onUpdateBatchInput(sAggregratedPointers); 7666c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7679580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7689580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7699580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 77029d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void mayEndBatchInput(final long eventTime) { 7716c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka synchronized (sAggregratedPointers) { 772c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); 7736c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 7746c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sInGesture = false; 7753623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onEndBatchInput(eventTime); 776b5fc0e02d04550d39bfa98c2dde805f1c1d3f9a3Tadashi G. Takaoka mTimerProxy.cancelAllUpdateBatchInputTimers(); 777b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (!mIsTrackingCanceled) { 778b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (DEBUG_LISTENER) { 779b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", 780b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mPointerId, sAggregratedPointers.getPointerSize())); 781b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 782b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mListener.onEndBatchInput(sAggregratedPointers); 783b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 7846c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7859580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7866f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka if (mIsTrackingCanceled) { 7876f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka return; 7886f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka } 78913ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this)); 7909580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7919580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 7928e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka private void cancelBatchInput() { 7938e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sPointerTrackerQueue.cancelAllPointerTracker(); 7948353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka mIsDetectingGesture = false; 7957c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka if (!sInGesture) { 7967c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka return; 7977c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka } 7988e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sInGesture = false; 7998e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka if (DEBUG_LISTENER) { 8008e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelBatchInput", mPointerId)); 8018e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } 8028e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka mListener.onCancelBatchInput(); 8038e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } 8048e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka 805694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void processMotionEvent(final int action, final int x, final int y, final long eventTime, 806694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 8078ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka switch (action) { 8088ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 8098ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 8108ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onDownEvent(x, y, eventTime, handler); 8118ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8128ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_UP: 8138ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 8148ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onUpEvent(x, y, eventTime); 8158ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8168ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 8173314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka onMoveEvent(x, y, eventTime, null); 8188ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8198ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 8208ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onCancelEvent(x, y, eventTime); 8218ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8228ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 8238ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 8248ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 825694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onDownEvent(final int x, final int y, final long eventTime, 826694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 827694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 828dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 829694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 830f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 83163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 832f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyboardActionListener(handler.getKeyboardActionListener()); 833f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 834baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 8358a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 836160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka if (deltaT < sParams.mTouchNoiseThresholdTime) { 837b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final int distance = getDistance(x, y, mLastX, mLastY); 838b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (distance < sParams.mTouchNoiseThresholdDistance) { 839faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 840b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onDownEvent:" 841b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " ignore potential noise: time=%d distance=%d", 842b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, deltaT, distance)); 8439bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 844b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance); 8459bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 846b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka cancelTracking(); 847baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 848baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 849baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 850baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 851eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final Key key = getKeyOn(x, y); 852b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onActualDownEvent(x, y); 85393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (key != null && key.isModifier()) { 85493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 85593b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 85693b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 8571d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 85893b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.add(this); 8591d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 8606c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!sShouldHandleGesture) { 8616c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 8626c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8634df6549c1a5ae2cdc2cdfafdad1ec2a75881134cTadashi G. Takaoka // A gesture should start only from a non-modifier key. 864b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() 865ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang && key != null && !key.isModifier(); 866b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (mIsDetectingGesture) { 867b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 8686c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sGestureFirstDownTime = eventTime; 8699580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 87058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime, 8713623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.getLastLetterTypingTime()); 872eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 8731d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8741d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 87535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private boolean isShowingMoreKeysPanel() { 87635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return (mMoreKeysPanel != null); 87735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 87835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 879694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void onDownEventInternal(final int x, final int y, final long eventTime) { 880e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onDownKey(x, y, eventTime); 88167a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 88232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. 883160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mIsAllowedSlidingKeyInput = sParams.mSlidingKeyInputEnabled 884c9f203805ca23276fcdcdc79b9298bc1d413ad98Tadashi G. Takaoka || (key != null && key.isModifier()) 88532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka || mKeyDetector.alwaysAllowsSlidingInput(); 8861a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 887b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mIsTrackingCanceled = false; 888f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 889e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 8901a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 891e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the new 8921a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 8932a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 894e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onDownKey(x, y, eventTime); 895e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 896996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 897e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 898e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 89929d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 9006a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9016a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9026a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 903694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startSlidingKeyInput(final Key key) { 904e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (!mIsInSlidingKeyInput) { 905f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = key.isModifier(); 906e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 907996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 908996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 909996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 910f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka private void resetSlidingKeyInput() { 911f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInput = false; 912f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = false; 91308d8a676c28f30a722629cb4713177064f6422e2Tadashi G. Takaoka mDrawingProxy.dismissSlidingKeyInputPreview(); 914f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka } 915f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka 9166c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onGestureMoveEvent(final int x, final int y, final long eventTime, 91702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final boolean isMajorEvent, final Key key) { 9186c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 9196c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (mIsDetectingGesture) { 920b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka final boolean onValidArea = mGestureStrokeWithPreviewPoints.addPointOnKeyboard( 921b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka x, y, gestureTime, isMajorEvent); 9228353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka // If the move event goes out from valid batch input area, cancel batch input. 923b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (!onValidArea) { 9248e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka cancelBatchInput(); 925b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka return; 926b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 927ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang // If the MoreKeysPanel is showing then do not attempt to enter gesture mode. However, 928ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang // the gestured touch points are still being recorded in case the panel is dismissed. 929ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 930ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang return; 931ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 9321645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka mayStartBatchInput(key); 933157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (sInGesture) { 934157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mayUpdateBatchInput(eventTime, key); 9359580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 9369580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 9379580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 9389580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 939694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) { 940694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_MOVE_EVENT) { 941dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 942694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 943b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (mIsTrackingCanceled) { 944e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 945694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 946baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 94735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (isShowingMoreKeysPanel()) { 94835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedX = mMoreKeysPanel.translateX(x); 94935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedY = mMoreKeysPanel.translateY(y); 95035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime); 95135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 95235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 9536c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture && me != null) { 954eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Add historical points to gesture path. 955eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int pointerIndex = me.findPointerIndex(mPointerId); 956eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalSize = me.getHistorySize(); 957eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int h = 0; h < historicalSize; h++) { 958eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalX = (int)me.getHistoricalX(pointerIndex, h); 959eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalY = (int)me.getHistoricalY(pointerIndex, h); 960eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final long historicalTime = me.getHistoricalEventTime(h); 9616c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onGestureMoveEvent(historicalX, historicalY, historicalTime, 96202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka false /* isMajorEvent */, null); 963eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 964eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 965ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 966ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 967ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang // Do not handle sliding keys (or show key pop-ups) when the MoreKeysPanel is visible. 968ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang return; 969ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 9706c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onMoveEventInternal(x, y, eventTime); 9716c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 9726c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 9733c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processSlidingKeyInput(final Key newKey, final int x, final int y, 9743c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime) { 9753c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 9763c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update key according 9773c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // to the new keyboard layout. 9783c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Key key = newKey; 9793c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 9803c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka key = onMoveKey(x, y); 9813c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9823c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onMoveToNewKey(key, x, y); 9833c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka startLongPressTimer(key); 9843c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 9853c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9863c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 9873c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processPhantomSuddenMoveHack(final Key key, final int x, final int y, 9883c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 9893c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 9903c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 9913c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " phantom sudden move event (distance=%d) is translated to " 9923c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, 9933c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka getDistance(x, y, lastX, lastY), 9943c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.mCode), 9953c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka x, y, Constants.printableCode(key.mCode))); 9963c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9973c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // TODO: This should be moved to outside of this nested if-clause? 9983c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (ProductionFlag.IS_EXPERIMENTAL) { 9993c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); 10003c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 100135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 10023c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 10033c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10043c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 10053c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processProximateBogusDownMoveUpEventHack(final Key key, final int x, final int y, 10063c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 10073c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 10083c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 10093c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 10103c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float radiusRatio = 10113c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mBogusMoveEventDetector.getDistanceFromDownEvent(x, y) 10123c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka / keyDiagonal; 10133c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 10143c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " bogus down-move-up event (raidus=%.2f key diagonal) is " 10153c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " translated to up[%d,%d,%s]/down[%d,%d,%s] events", 10163c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mPointerId, radiusRatio, 10173c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.mCode), 10183c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka x, y, Constants.printableCode(key.mCode))); 10193c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 102035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 10213c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 10223c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10233c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 1024831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka private void processSildeOutFromOldKey(final Key oldKey) { 1025831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 1026831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 1027831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka startSlidingKeyInput(oldKey); 1028831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1029831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } 1030831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka 10313c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void slideFromOldKeyToNewKey(final Key key, final int x, final int y, 10328b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 10338b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 10348b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 10358b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onPress() to notify that the new key is being pressed. 1036831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSildeOutFromOldKey(oldKey); 10378b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka startRepeatKey(key); 10388b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 10393c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka processSlidingKeyInput(key, x, y, eventTime); 10402a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 10412a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be reported as a sudden move by 10422a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // touch panel firmware. This hack detects such cases and translates the move event to 10432a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // successive up and down events. 10442a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // TODO: Should find a way to balance gesture detection and this hack. 10452a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsPhantomSuddenMoveEventHack 10462a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) { 10472a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processPhantomSuddenMoveHack(key, x, y, eventTime, oldKey, lastX, lastY); 10482a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 10492a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive proximate touches may be reported as a bogus 10502a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // down-move-up event by touch panel firmware. This hack detects such cases and breaks 10512a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // these events into separate up and down events. 10522a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsProximateBogusDownMoveUpEventHack && sTimeRecorder.isInFastTyping(eventTime) 10532a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { 10542a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY); 10552a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 10562a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: If there are currently multiple touches, register the key even if the finger 10572a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // slides off the key. This defends against noise from some touch panels when there are 10582a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // close multiple touches. 10592a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // Caveat: When in chording input mode with a modifier key, we don't use this hack. 106093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka else if (getActivePointerTrackerCount() > 1 10612a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { 10622a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (DEBUG_MODE) { 10632a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 10642a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka + " detected sliding finger while multi touching", mPointerId)); 10653c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10662a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka onUpEvent(x, y, eventTime); 1067b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka cancelTracking(); 10682a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka setReleasedKeyGraphics(oldKey); 10692a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } else { 10702a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (!mIsDetectingGesture) { 1071b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka cancelTracking(); 10728b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10732a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka setReleasedKeyGraphics(oldKey); 10748b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10758b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10768b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 10778b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka private void slideOutFromOldKey(final Key oldKey, final int x, final int y) { 10788b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 10798b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // notify that the previous key has been released. 1080831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSildeOutFromOldKey(oldKey); 10818b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 10828b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onMoveToNewKey(null, x, y); 10838b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } else { 10848b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (!mIsDetectingGesture) { 1085b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka cancelTracking(); 10868b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10878b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10888b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10898b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 10906c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onMoveEventInternal(final int x, final int y, final long eventTime) { 10918a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 10928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 1093e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key oldKey = mCurrentKey; 10948b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final Key newKey = onMoveKey(x, y); 1095eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 10966c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture) { 10976c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // Register move event on gesture tracker. 10988b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey); 10996c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 11006c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 11016c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 11026c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 11036c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 1104eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1105eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 11068b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (newKey != null) { 11073c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 11088b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka slideFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY); 11093c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } else if (oldKey == null) { 1110831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 1111831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 1112831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSlidingKeyInput(newKey, x, y, eventTime); 1113c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 1114831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } else { // newKey == null 11158b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 11168b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka slideOutFromOldKey(oldKey, x, y); 111707221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 11186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1119547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka mDrawingProxy.showSlidingKeyInputPreview(this); 11206a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11216a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1122694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onUpEvent(final int x, final int y, final long eventTime) { 1123694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1124dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 1125694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 11261d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 112793b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (!sInGesture) { 112893b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (mCurrentKey != null && mCurrentKey.isModifier()) { 112993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing an up event of modifier key, all pointers already being 113093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 113193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime); 113293b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka } else { 113393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime); 11341d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 11351d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 113635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 113793b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 11381d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 11391d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1140d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 1141d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 1142d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 11430cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 1144694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onPhantomUpEvent(final long eventTime) { 1145694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1146547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka printTouchEvent("onPhntEvent:", mLastX, mLastY, eventTime); 1147694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 114835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (isShowingMoreKeysPanel()) { 114935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return; 115035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 115135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(mLastX, mLastY, eventTime); 1152b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka cancelTracking(); 11531d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 11541d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 115535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private void onUpEventInternal(final int x, final int y, final long eventTime) { 11562321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1157f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 11586c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIsDetectingGesture = false; 11596c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final Key currentKey = mCurrentKey; 11606c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 11615a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka // Release the last pressed key. 11626c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(currentKey); 116335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 116435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (isShowingMoreKeysPanel()) { 116535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (!mIsTrackingCanceled) { 116635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedX = mMoreKeysPanel.translateX(x); 116735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedY = mMoreKeysPanel.translateY(y); 116835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.onUpEvent(translatedX, translatedY, mPointerId, eventTime); 116935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 117035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.dismissMoreKeysPanel(); 117135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel = null; 117235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return; 11739ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 1174eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 11756c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 11766c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null) { 11776c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka callListenerOnRelease(currentKey, currentKey.mCode, true); 1178eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 117929d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka mayEndBatchInput(eventTime); 1180eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 1181eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 118258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 1183b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (mIsTrackingCanceled) { 1184d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 1185694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 11866c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null && !currentKey.isRepeatable()) { 11873623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime); 11886a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11896a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11906a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 119135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang public void onShowMoreKeysPanel(final int translatedX, final int translatedY, 119235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final MoreKeysPanel panel) { 119335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang setReleasedKeyGraphics(mCurrentKey); 119435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final long eventTime = SystemClock.uptimeMillis(); 119535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel = panel; 119635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.onDownEvent(translatedX, translatedY, mPointerId, eventTime); 11979ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 11989ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 1199b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka @Override 1200b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public void cancelTracking() { 12018353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka if (isShowingMoreKeysPanel()) { 12028353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka return; 12038353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka } 1204b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mIsTrackingCanceled = true; 1205b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1206b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 1207906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 1208547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka resetSlidingKeyInput(); 1209b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka cancelTracking(); 1210e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 121193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 1212d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 1213d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 1214694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onCancelEvent(final int x, final int y, final long eventTime) { 1215694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1216dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 1217694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 12181d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 12197c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka cancelBatchInput(); 12208e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sPointerTrackerQueue.cancelAllPointerTracker(); 12218e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 1222baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 12231d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 12241d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1225baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 12262321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1227e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 1228f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 1229ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 1230ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang mMoreKeysPanel.dismissMoreKeysPanel(); 1231ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang mMoreKeysPanel = null; 1232ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 12336a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12346a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1235694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startRepeatKey(final Key key) { 12366c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (key != null && key.isRepeatable() && !sInGesture) { 12376662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv onRegisterKey(key); 1238a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(this); 1239a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1240a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1241a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 1242694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onRegisterKey(final Key key) { 1243c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka if (key != null) { 12443623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis()); 1245d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 1246c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 12476a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12486a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1249b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, 1250b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final Key newKey) { 1251694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyDetector == null) { 1252a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 1253694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1254694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final Key curKey = mCurrentKey; 12556a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 1256e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 1257a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1258a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (curKey == null /* && newKey != null */) { 1259a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1260a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1261a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka // Here curKey points to the different key from newKey. 1262a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( 1263a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mIsInSlidingKeyInputFromModifier); 1264a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); 1265a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { 1266a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1267a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared) 1268a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka / mKeyboard.mMostCommonKeyWidth; 1269a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1270a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka +" %.2f key width from key edge", mPointerId, distanceToEdgeRatio)); 1271b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1272a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1273a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1274a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput 1275a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && sTimeRecorder.isInFastTyping(eventTime) 1276a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) { 1277a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1278a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 1279a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 1280a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float lengthFromDownRatio = 1281a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal; 1282a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1283a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka + " %.2f key diagonal from virtual down point", 1284a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mPointerId, lengthFromDownRatio)); 1285b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1286e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 12876a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1288a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return false; 12896a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12906a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1291694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startLongPressTimer(final Key key) { 12926c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (key != null && key.isLongPressEnabled() && !sInGesture) { 1293a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startLongPressTimer(this); 12944189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 129566e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 129666e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 12973623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) { 129883e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 12998aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 1300dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 1301dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 130266e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 1303694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final int code = key.mCode; 13043623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka callListenerOnCodeInput(key, code, x, y, eventTime); 13052013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka callListenerOnRelease(key, code, false); 13066a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 13076a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1308694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void printTouchEvent(final String title, final int x, final int y, 1309694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final long eventTime) { 1310723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka final Key key = mKeyDetector.detectHitKey(x, y); 1311e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka final String code = KeyDetector.printableCode(key); 131258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, 1313b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka (mIsTrackingCanceled ? "-" : " "), title, x, y, eventTime, code)); 1314dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 13156e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 1316