PointerTracker.java revision 93b5c2ce63705e7ebffd9bdb7358100e8d5b5235
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; 31f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 32faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 335509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport com.android.inputmethod.latin.R; 349bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 356b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 366a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 375c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 38dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 39a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class PointerTracker implements PointerTrackerQueue.Element { 40dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 41dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 42dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 43dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 44b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG || DEBUG_EVENT; 4540a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 460657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka /** True if {@link PointerTracker}s should handle gesture events. */ 470657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka private static boolean sShouldHandleGesture = false; 488335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sMainDictionaryAvailable = false; 498335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByInputField = false; 508335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByUser = false; 51918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 52f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public interface KeyEventHandler { 53f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 54f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyDetector object that is used for this PointerTracker. 55f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyDetector object that is used for this PointerTracker 56f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 57f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyDetector getKeyDetector(); 58f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 59f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 60f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyboardActionListener object that is used to register key code and so on. 61f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyboardActionListner for this PointerTracker 62f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 63f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener(); 64f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 65f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 66f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get DrawingProxy object that is used for this PointerTracker. 67f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the DrawingProxy object that is used for this PointerTracker 68f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 69f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy(); 70f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 71f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 72f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get TimerProxy object that handles key repeat and long press timer event for this 73f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * PointerTracker. 74f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the TimerProxy object that handles key repeat and long press timer event. 75f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 76f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public TimerProxy getTimerProxy(); 77f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 78f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 799d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public interface DrawingProxy extends MoreKeysPanel.Controller { 806a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public void invalidateKey(Key key); 81e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public void showKeyPreview(PointerTracker tracker); 82d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void dismissKeyPreview(PointerTracker tracker); 83f0e83046f022b5594f98aef07fbda7f2f837f262Tadashi G. Takaoka public void showGesturePreviewTrail(PointerTracker tracker, boolean isOldestTracker); 846a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 856a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 862321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public interface TimerProxy { 87d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey); 8873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState(); 89a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker); 90a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker); 91a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code); 9298b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer(); 930ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer(); 94beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer(); 950ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout(); 962321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelKeyTimers(); 9729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 9829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static class Adapter implements TimerProxy { 9929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 100d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey) {} 10193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 10273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { return false; } 10393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 104a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker) {} 10529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 106a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker) {} 107a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 108a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code) {} 10929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 11029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelLongPressTimer() {} 11129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 1120ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer() {} 1130ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 114beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer() {} 115beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 1160ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout() { return false; } 1170ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 11829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelKeyTimers() {} 11929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 1202321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka } 1212321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka 122a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka static final class PointerTrackerParams { 1235509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final boolean mSlidingKeyInputEnabled; 1245509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final int mTouchNoiseThresholdTime; 125b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public final int mTouchNoiseThresholdDistance; 1263623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public final int mSuppressKeyPreviewAfterBatchInputDuration; 1275509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1285509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); 1295509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1305509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private PointerTrackerParams() { 1315509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = false; 1325509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = 0; 133b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = 0; 1343623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 0; 1355509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1365509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 13780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) { 1385509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean( 1395509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_slidingKeyInputEnable, false); 1405509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( 1415509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); 142b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( 1435509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); 1443623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt( 1453623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0); 1465509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1475509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1485509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 149160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka // Parameters for pointer handling. 1505509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private static PointerTrackerParams sParams; 15180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private static GestureStrokeParams sGestureStrokeParams; 152d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka private static boolean sNeedsPhantomSuddenMoveEventHack; 153b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move this threshold to resource. 154b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // TODO: Device specific parameter would be better for device specific hack? 155b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth 156b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // This hack might be device specific. 157b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final boolean sNeedsProximateBogusDownMoveUpEventHack = true; 1585c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1595f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); 16093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue(); 1615c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1625c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 1636a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1640efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 1650efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 166a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 167dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private KeyboardActionListener mListener = EMPTY_LISTENER; 168baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1695a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 170b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mPhantonSuddenMoveThreshold; 171b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); 1726a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1736c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private boolean mIsDetectingGesture = false; // per PointerTracker. 1746c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static boolean sInGesture = false; 1756c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static long sGestureFirstDownTime; 1763623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private static TimeRecorder sTimeRecorder; 1776c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static final InputPointers sAggregratedPointers = new InputPointers( 1786c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka GestureStroke.DEFAULT_CAPACITY); 17958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers 18058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers 1819580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 182b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static final class BogusMoveEventDetector { 183b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move these thresholds to resource. 184d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // These thresholds' unit is a diagonal length of a key. 185d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f; 186d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f; 187b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 188b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mAccumulatedDistanceThreshold; 189b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mRadiusThreshold; 190b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 191b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Accumulated distance from actual and artificial down keys. 192b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int mAccumulatedDistanceFromDownKey; 193b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownX; 194b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownY; 195b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 196d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public void setKeyboardGeometry(final int keyWidth, final int keyHeight) { 197d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight); 198b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceThreshold = (int)( 199d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); 200d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD); 201b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 202b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 203b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onActualDownEvent(final int x, final int y) { 204b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownX = x; 205b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownY = y; 206b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 207b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 208b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onDownKey() { 209b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey = 0; 210b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 211b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 212b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onMoveKey(final int distance) { 213b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey += distance; 214b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 215b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 216d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public boolean hasTraveledLongDistance(final int x, final int y) { 217d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dx = Math.abs(x - mActualDownX); 218d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dy = Math.abs(y - mActualDownY); 219d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // A bogus move event should be a horizontal movement. A vertical movement might be 220d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // a sloppy typing and should be ignored. 221d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; 222b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 223b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 224b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int getDistanceFromDownEvent(final int x, final int y) { 225b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistance(x, y, mActualDownX, mActualDownY); 226b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 227b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 228b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isCloseToActualDownEvent(final int x, final int y) { 229b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistanceFromDownEvent(x, y) < mRadiusThreshold; 230b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 231b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 232b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2333623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka static final class TimeRecorder { 2343623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mSuppressKeyPreviewAfterBatchInputDuration; 2353623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mStaticTimeThresholdAfterFastTyping; // msec 2363623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastTypingTime; 2373623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastLetterTypingTime; 2383623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastBatchInputTime; 2393623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2403623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public TimeRecorder(final PointerTrackerParams pointerTrackerParams, 2413623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final GestureStrokeParams gestureStrokeParams) { 2423623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 2433623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka pointerTrackerParams.mSuppressKeyPreviewAfterBatchInputDuration; 2443623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = 2453623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka gestureStrokeParams.mStaticTimeThresholdAfterFastTyping; 2463623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2473623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 248b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isInFastTyping(final long eventTime) { 249b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; 250b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; 251b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 252b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2537a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka private boolean wasLastInputTyping() { 2547a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return mLastTypingTime >= mLastBatchInputTime; 2553623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2563623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2573623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onCodeInput(final int code, final long eventTime) { 2587a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // Record the letter typing time when 2597a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 1. Letter keys are typed successively without any batch input in between. 2607a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 2. A letter key is typed within the threshold time since the last any key typing. 2617a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 3. A non-letter key is typed within the threshold time since the last letter key 2627a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // typing. 2637a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (Character.isLetter(code)) { 2647a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (wasLastInputTyping() 2657a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) { 2667a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2673623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2683623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } else { 2693623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) { 2703623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // This non-letter typing should be treated as a part of fast typing. 2717a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2723623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2733623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2747a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastTypingTime = eventTime; 2753623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2763623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2773623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onEndBatchInput(final long eventTime) { 2787a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastBatchInputTime = eventTime; 2793623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2803623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2813623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public long getLastLetterTypingTime() { 2823623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return mLastLetterTypingTime; 2833623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2843623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2853623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 2867a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return !wasLastInputTyping() 2873623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration; 2883623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2893623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2903623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2918a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 2928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 2938a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 2948a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 295e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The current key where this pointer is. 296e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mCurrentKey = null; 297e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The position where the current key was recognized for the first time. 2988a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 2998a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 3008a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3018a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 3028a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 3038a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 3046a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3051a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 3061a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 3071a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 3089ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka // true if event is already translated to a key action. 309c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka private boolean mKeyAlreadyProcessed; 310c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 3119d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka // true if this pointer has been long-pressed and is showing a more keys panel. 3129d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private boolean mIsShowingMoreKeysPanel; 3139ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 314f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input. 3155c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 316f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input from a modifier key, 317f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // so that further modifier keys should be ignored. 318f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka boolean mIsInSlidingKeyInputFromModifier; 319cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 320f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if a sliding key input is allowed. 32167a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 32267a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 323dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Empty {@link KeyboardActionListener} 324e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka private static final KeyboardActionListener EMPTY_LISTENER = 325e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka new KeyboardActionListener.Adapter(); 3266e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka 327c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; 328f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 32993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka public static void init(final boolean needsPhantomSuddenMoveEventHack) { 330d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack; 3315509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = PointerTrackerParams.DEFAULT; 33280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = GestureStrokeParams.DEFAULT; 3333623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 334160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 33593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3365509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static void setParameters(final TypedArray mainKeyboardViewAttr) { 3375509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = new PointerTrackerParams(mainKeyboardViewAttr); 33880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr); 3393623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 3406a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3416a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3428335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static void updateGestureHandlingMode() { 3438335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sShouldHandleGesture = sMainDictionaryAvailable 3448335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByInputField 3458335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByUser 3468335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); 3478335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 3488335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 3498335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 350694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 3518335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sMainDictionaryAvailable = mainDictionaryAvailable; 3528335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 3538335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 3548335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 355694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 3568335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; 3578335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 358918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka } 359918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 360694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, final KeyEventHandler handler) { 361b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka final ArrayList<PointerTracker> trackers = sTrackers; 3625c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3635c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 3645c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 3655c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 3665c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 3675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3685c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3695c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 3705c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3715c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3725c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 37393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.isAnyInSlidingKeyInput(); 3745c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 376694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyboardActionListener(final KeyboardActionListener listener) { 377afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 378afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 379afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 3805c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 3815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3825c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3835c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 384694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyDetector(final KeyDetector keyDetector) { 385afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 386afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 387afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 3885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 3895c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 3905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 3915c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 392918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 3938335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput(); 3948335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 3955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3965c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 397dde36ef34329164cf8b8a3985c578dab0343b3ebTadashi G. Takaoka public static void setReleasedKeyGraphicsToAllKeys() { 398afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 399afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 400afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 401e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.mCurrentKey); 4025c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4035c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4045c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 405694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private PointerTracker(final int id, final KeyEventHandler handler) { 406694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (handler == null) { 4075c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 408694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 4095c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 41080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints( 41180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka id, sGestureStrokeParams); 4125c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 4135c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 4145c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 4155c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 4166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4176a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 4181a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 419694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key) { 4206c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 421eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return false; 422eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 423f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 424e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 42558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId, 42658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka KeyDetector.printableCode(key), 42758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka ignoreModifierKey ? " ignoreModifier" : "", 42858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "" : " disabled")); 429e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 43093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (ignoreModifierKey) { 431996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 43293246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 433e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 4342a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onPressKey(key.mCode); 435690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 436690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 437d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 438690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 439690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 440690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 441dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 442dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 443690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 444690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 445694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, 4463623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final int y, final long eventTime) { 447f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 4486bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 44929d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int code = altersCode ? key.getAltCode() : primaryCode; 4502013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (DEBUG_LISTENER) { 451240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final String output = code == Constants.CODE_OUTPUT_TEXT 452240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka ? key.getOutputText() : Constants.printableCode(code); 45358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y, 45458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka output, ignoreModifierKey ? " ignoreModifier" : "", 45558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled")); 4562013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4579bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4589bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, 4599bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge altersCode, code); 4609bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 461e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 462996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 463e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 4646bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 4656bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.isEnabled() || altersCode) { 4663623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onCodeInput(code, eventTime); 467240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (code == Constants.CODE_OUTPUT_TEXT) { 46829d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka mListener.onTextInput(key.getOutputText()); 469240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (code != Constants.CODE_UNSPECIFIED) { 470ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mListener.onCodeInput(code, x, y); 4712013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 47293246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 473dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 474dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 475f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may be in shifted state and the 476690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 477694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnRelease(final Key key, final int primaryCode, 478694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final boolean withSliding) { 4796c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 480eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 481eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 482f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 483e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 48458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, 485240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka Constants.printableCode(primaryCode), 48658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "", 48758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "": " disabled")); 488e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 4899bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4909bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, 4919bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ignoreModifierKey); 4929bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 493e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 494996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 495e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 49693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (key.isEnabled()) { 4972a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onReleaseKey(primaryCode, withSliding); 49893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 499dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 500dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 5018aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 502694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_LISTENER) { 50358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelInput", mPointerId)); 504694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 5059bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 5069bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCancelInput(); 5079bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 5088aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 509dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 510dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 511694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setKeyDetectorInner(final KeyDetector keyDetector) { 51258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 51358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (keyDetector == mKeyDetector && keyboard == mKeyboard) { 51458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return; 51558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 516a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 5175a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 518d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyWidth = mKeyboard.mMostCommonKeyWidth; 519d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyHeight = mKeyboard.mMostCommonKeyHeight; 520d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth); 5218a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); 5228a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (newKey != mCurrentKey) { 5238a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (mDrawingProxy != null) { 5248a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 5258a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 52644972bcdb6f6dd0e4f02a26f31c7effaf0525403Tadashi G. Takaoka // Keep {@link #mCurrentKey} that comes from previous keyboard. 5278a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 528b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); 529d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mBogusMoveEventDetector.setKeyboardGeometry(keyWidth, keyHeight); 5305a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 5315a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 5320cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 533cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 534cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 535cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 536cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 537e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKey() { 538e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey; 539dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 540dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 5410cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 5422aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 543e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey != null && mCurrentKey.isModifier(); 5442aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 5452aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 546694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public Key getKeyOn(final int x, final int y) { 547723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 5482aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 5492aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 550694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setReleasedKeyGraphics(final Key key) { 551d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 5526bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 553faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 554faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 555faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 5566bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, update the key release graphics just in case. 557faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(key); 558faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 559faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 560faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 561faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 562faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(shiftKey); 5632013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5642013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 565faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 5662013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 567faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.altCodeWhileTyping()) { 56829d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 569faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 570faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 571faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(altKey); 572faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 573faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 57429d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 575faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(k); 5762013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5772013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5786a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5796a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5806a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 58129d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 58229d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!sShouldHandleGesture) return false; 5833623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime); 58429d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka } 58529d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka 58629d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void setPressedKeyGraphics(final Key key, final long eventTime) { 5876bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 5886bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka return; 5896bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 5906bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka 5916bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 5926bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 5936bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; 5946bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (!needsToUpdateGraphics) { 595faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 596faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 597faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 59829d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!key.noKeyPreview() && !sInGesture && !needsToSuppressKeyPreviewPopup(eventTime)) { 599faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.showKeyPreview(this); 600faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 601faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(key); 602faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 603faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 604faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 605faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 606faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(shiftKey); 6072013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6082013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 609faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 6102013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 61173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) { 61229d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 613faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 614faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 615faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(altKey); 616faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 617faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 61829d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 619faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(k); 6202013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6212013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 622d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 623c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 624c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 625694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updateReleaseKeyGraphics(final Key key) { 626faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onReleased(); 627faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 628faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 629faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 630694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updatePressKeyGraphics(final Key key) { 631faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onPressed(); 632faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 633faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 634faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 635c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { 636c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka return mGestureStrokeWithPreviewPoints; 6372f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 6382f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang 6398a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastX() { 6408a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastX; 6418a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6428a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 6438a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastY() { 6448a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastY; 6458a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6468a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 6478a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 6488a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 6498a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6508a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 651694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onDownKey(final int x, final int y, final long eventTime) { 6528a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 653b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onDownKey(); 6548a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 6558a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6568a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 657b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static int getDistance(final int x1, final int y1, final int x2, final int y2) { 658b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return (int)Math.hypot(x1 - x2, y1 - y2); 659b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 660b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 661694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKeyInternal(final int x, final int y) { 662b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onMoveKey(getDistance(x, y, mLastX, mLastY)); 6638a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 6648a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 665723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 6668a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6678a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 668694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKey(final int x, final int y) { 6698a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 6708a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6718a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 672694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveToNewKey(final Key newKey, final int x, final int y) { 673e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mCurrentKey = newKey; 6748a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 6758a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 676e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return newKey; 6778a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6788a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 6796c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static int getActivePointerTrackerCount() { 68093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.size(); 6816c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 6826c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 68313ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka private static boolean isOldestTrackerInQueue(final PointerTracker tracker) { 68493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.getOldestElement() == tracker; 68513ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka } 68613ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka 6871645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka private void mayStartBatchInput(final Key key) { 688c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { 6899c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka return; 6909c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka } 6911645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka if (key == null || !Character.isLetter(key.mCode)) { 6921645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka return; 6931645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka } 6949c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka if (DEBUG_LISTENER) { 69558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); 6969580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 6979c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka sInGesture = true; 69858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka synchronized (sAggregratedPointers) { 69958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sAggregratedPointers.reset(); 70058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionPointSize = 0; 70158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionTime = 0; 70258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mListener.onStartBatchInput(); 70358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 704ad181915f78235bc09e88c85ed9df669801b8442Tadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 70513ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this)); 7066c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7076c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 708157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka private void mayUpdateBatchInput(final long eventTime, final Key key) { 709157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (key != null) { 710157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka synchronized (sAggregratedPointers) { 71180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka final GestureStroke stroke = mGestureStrokeWithPreviewPoints; 71280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka stroke.appendIncrementalBatchPoints(sAggregratedPointers); 713157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka final int size = sAggregratedPointers.getPointerSize(); 714157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (size > sLastRecognitionPointSize 71580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) { 716157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka sLastRecognitionPointSize = size; 717157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka sLastRecognitionTime = eventTime; 718157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (DEBUG_LISTENER) { 71958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", 72058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, size)); 721157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka } 722157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mListener.onUpdateBatchInput(sAggregratedPointers); 7236c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7246c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7259580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 72613ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this)); 7279580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7289580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 72929d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void mayEndBatchInput(final long eventTime) { 7306c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka synchronized (sAggregratedPointers) { 731c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); 7326c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 7336c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (DEBUG_LISTENER) { 73458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", 73558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, sAggregratedPointers.getPointerSize())); 7366c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7376c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sInGesture = false; 7383623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onEndBatchInput(eventTime); 7396c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mListener.onEndBatchInput(sAggregratedPointers); 7406c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7419580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 74213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTrackerInQueue(this)); 7439580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7449580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 745694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void processMotionEvent(final int action, final int x, final int y, final long eventTime, 746694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 7478ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka switch (action) { 7488ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 7498ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 7508ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onDownEvent(x, y, eventTime, handler); 7518ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 7528ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_UP: 7538ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 7548ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onUpEvent(x, y, eventTime); 7558ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 7568ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 7573314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka onMoveEvent(x, y, eventTime, null); 7588ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 7598ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 7608ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onCancelEvent(x, y, eventTime); 7618ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 7628ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 7638ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 7648ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 765694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onDownEvent(final int x, final int y, final long eventTime, 766694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 767694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 768dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 769694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 7701d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 771f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 77263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 773f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyboardActionListener(handler.getKeyboardActionListener()); 774f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 775baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 7768a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 777160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka if (deltaT < sParams.mTouchNoiseThresholdTime) { 778b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final int distance = getDistance(x, y, mLastX, mLastY); 779b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (distance < sParams.mTouchNoiseThresholdDistance) { 780faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 781b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onDownEvent:" 782b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " ignore potential noise: time=%d distance=%d", 783b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, deltaT, distance)); 7849bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 785b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance); 7869bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 787d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 788baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 789baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 790baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 791baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 792eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final Key key = getKeyOn(x, y); 793b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onActualDownEvent(x, y); 79493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (key != null && key.isModifier()) { 79593b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 79693b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 79793b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 7981d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 79993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.add(this); 8001d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 8016c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!sShouldHandleGesture) { 8026c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 8036c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8044df6549c1a5ae2cdc2cdfafdad1ec2a75881134cTadashi G. Takaoka // A gesture should start only from a non-modifier key. 805b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() 8064df6549c1a5ae2cdc2cdfafdad1ec2a75881134cTadashi G. Takaoka && !mIsShowingMoreKeysPanel && key != null && !key.isModifier(); 807b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (mIsDetectingGesture) { 808b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 8096c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sGestureFirstDownTime = eventTime; 8109580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 81158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime, 8123623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.getLastLetterTypingTime()); 813eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 8141d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8151d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 816694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void onDownEventInternal(final int x, final int y, final long eventTime) { 817e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onDownKey(x, y, eventTime); 81867a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 81932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. 820160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mIsAllowedSlidingKeyInput = sParams.mSlidingKeyInputEnabled 821c9f203805ca23276fcdcdc79b9298bc1d413ad98Tadashi G. Takaoka || (key != null && key.isModifier()) 82232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka || mKeyDetector.alwaysAllowsSlidingInput(); 8231a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 824c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka mKeyAlreadyProcessed = false; 825f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 826e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 8271a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 828e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the new 8291a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 8302a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 831e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onDownKey(x, y, eventTime); 832e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 833996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 834e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 835e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 83629d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 8376a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 8386a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 8396a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 840694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startSlidingKeyInput(final Key key) { 841e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (!mIsInSlidingKeyInput) { 842f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = key.isModifier(); 843e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 844996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 845996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 846996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 847f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka private void resetSlidingKeyInput() { 848f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInput = false; 849f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = false; 850f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka } 851f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka 8526c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onGestureMoveEvent(final int x, final int y, final long eventTime, 85302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final boolean isMajorEvent, final Key key) { 8546c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 8556c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (mIsDetectingGesture) { 85602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isMajorEvent); 8571645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka mayStartBatchInput(key); 858157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (sInGesture) { 859157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mayUpdateBatchInput(eventTime, key); 8609580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8619580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8629580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8639580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 864694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) { 865694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_MOVE_EVENT) { 866dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 867694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 868694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyAlreadyProcessed) { 869e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 870694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 871baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 8726c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture && me != null) { 873eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Add historical points to gesture path. 874eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int pointerIndex = me.findPointerIndex(mPointerId); 875eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalSize = me.getHistorySize(); 876eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int h = 0; h < historicalSize; h++) { 877eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalX = (int)me.getHistoricalX(pointerIndex, h); 878eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalY = (int)me.getHistoricalY(pointerIndex, h); 879eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final long historicalTime = me.getHistoricalEventTime(h); 8806c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onGestureMoveEvent(historicalX, historicalY, historicalTime, 88102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka false /* isMajorEvent */, null); 882eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 883eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 884eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 8856c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onMoveEventInternal(x, y, eventTime); 8866c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8876c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 8883c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processSlidingKeyInput(final Key newKey, final int x, final int y, 8893c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime) { 8903c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 8913c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update key according 8923c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // to the new keyboard layout. 8933c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Key key = newKey; 8943c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 8953c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka key = onMoveKey(x, y); 8963c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 8973c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onMoveToNewKey(key, x, y); 8983c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka startLongPressTimer(key); 8993c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 9003c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9013c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 9023c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processPhantomSuddenMoveHack(final Key key, final int x, final int y, 9033c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 9043c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 9053c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 9063c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " phantom sudden move event (distance=%d) is translated to " 9073c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, 9083c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka getDistance(x, y, lastX, lastY), 9093c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.mCode), 9103c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka x, y, Constants.printableCode(key.mCode))); 9113c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9123c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // TODO: This should be moved to outside of this nested if-clause? 9133c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (ProductionFlag.IS_EXPERIMENTAL) { 9143c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); 9153c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9163c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onUpEventInternal(eventTime); 9173c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 9183c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9193c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 9203c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processProximateBogusDownMoveUpEventHack(final Key key, final int x, final int y, 9213c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 9223c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 9233c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 9243c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 9253c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float radiusRatio = 9263c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mBogusMoveEventDetector.getDistanceFromDownEvent(x, y) 9273c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka / keyDiagonal; 9283c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 9293c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " bogus down-move-up event (raidus=%.2f key diagonal) is " 9303c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " translated to up[%d,%d,%s]/down[%d,%d,%s] events", 9313c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mPointerId, radiusRatio, 9323c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.mCode), 9333c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka x, y, Constants.printableCode(key.mCode))); 9343c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9353c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onUpEventInternal(eventTime); 9363c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 9373c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9383c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 939831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka private void processSildeOutFromOldKey(final Key oldKey) { 940831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 941831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 942831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka startSlidingKeyInput(oldKey); 943831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 944831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } 945831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka 9463c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void slideFromOldKeyToNewKey(final Key key, final int x, final int y, 9478b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 9488b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 9498b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 9508b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onPress() to notify that the new key is being pressed. 951831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSildeOutFromOldKey(oldKey); 9528b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka startRepeatKey(key); 9538b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 9543c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka processSlidingKeyInput(key, x, y, eventTime); 9552a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 9562a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be reported as a sudden move by 9572a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // touch panel firmware. This hack detects such cases and translates the move event to 9582a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // successive up and down events. 9592a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // TODO: Should find a way to balance gesture detection and this hack. 9602a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsPhantomSuddenMoveEventHack 9612a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) { 9622a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processPhantomSuddenMoveHack(key, x, y, eventTime, oldKey, lastX, lastY); 9632a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 9642a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive proximate touches may be reported as a bogus 9652a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // down-move-up event by touch panel firmware. This hack detects such cases and breaks 9662a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // these events into separate up and down events. 9672a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsProximateBogusDownMoveUpEventHack && sTimeRecorder.isInFastTyping(eventTime) 9682a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { 9692a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY); 9702a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 9712a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: If there are currently multiple touches, register the key even if the finger 9722a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // slides off the key. This defends against noise from some touch panels when there are 9732a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // close multiple touches. 9742a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // Caveat: When in chording input mode with a modifier key, we don't use this hack. 97593b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka else if (getActivePointerTrackerCount() > 1 9762a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { 9772a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (DEBUG_MODE) { 9782a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 9792a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka + " detected sliding finger while multi touching", mPointerId)); 9803c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9812a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka onUpEvent(x, y, eventTime); 9822a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka mKeyAlreadyProcessed = true; 9832a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka setReleasedKeyGraphics(oldKey); 9842a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } else { 9852a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (!mIsDetectingGesture) { 9862a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka mKeyAlreadyProcessed = true; 9878b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 9882a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka setReleasedKeyGraphics(oldKey); 9898b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 9908b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 9918b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 9928b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka private void slideOutFromOldKey(final Key oldKey, final int x, final int y) { 9938b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 9948b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // notify that the previous key has been released. 995831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSildeOutFromOldKey(oldKey); 9968b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 9978b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onMoveToNewKey(null, x, y); 9988b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } else { 9998b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (!mIsDetectingGesture) { 10008b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka mKeyAlreadyProcessed = true; 10018b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10028b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10038b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10048b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 10056c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onMoveEventInternal(final int x, final int y, final long eventTime) { 10068a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 10078a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 1008e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key oldKey = mCurrentKey; 10098b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final Key newKey = onMoveKey(x, y); 1010eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 10116c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture) { 10126c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // Register move event on gesture tracker. 10138b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey); 10146c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 10156c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 10166c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 10176c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 10186c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 1019eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1020eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 10218b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (newKey != null) { 10223c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 10238b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka slideFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY); 10243c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } else if (oldKey == null) { 1025831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 1026831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 1027831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSlidingKeyInput(newKey, x, y, eventTime); 1028c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 1029831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } else { // newKey == null 10308b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 10318b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka slideOutFromOldKey(oldKey, x, y); 103207221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 10336a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10346a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10356a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1036694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onUpEvent(final int x, final int y, final long eventTime) { 1037694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1038dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 1039694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 10401d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 104193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (!sInGesture) { 104293b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (mCurrentKey != null && mCurrentKey.isModifier()) { 104393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing an up event of modifier key, all pointers already being 104493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 104593b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime); 104693b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka } else { 104793b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime); 10481d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 10491d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 1050630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 105193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 10521d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 10531d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1054d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 1055d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 1056d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 10570cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 1058694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onPhantomUpEvent(final long eventTime) { 1059694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 10600cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime); 1061694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1062630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 1063d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 10641d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 10651d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1066630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka private void onUpEventInternal(final long eventTime) { 10672321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1068f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 10696c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIsDetectingGesture = false; 10706c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final Key currentKey = mCurrentKey; 10716c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 10725a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka // Release the last pressed key. 10736c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(currentKey); 10749d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 10759d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 10769d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 10779ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 1078eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 10796c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 10806c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null) { 10816c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka callListenerOnRelease(currentKey, currentKey.mCode, true); 1082eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 108329d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka mayEndBatchInput(eventTime); 1084eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 1085eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 108658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 1087694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyAlreadyProcessed) { 1088d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 1089694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 10906c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null && !currentKey.isRepeatable()) { 10913623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime); 10926a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10936a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10946a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1095694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) { 10969ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka onLongPressed(); 10979d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = true; 1098cc3500b0c8f11e8de1ad7376dda466d30637e462Tadashi G. Takaoka onDownEvent(x, y, SystemClock.uptimeMillis(), handler); 10999ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 11009ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 1101906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 1102d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 1103e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 110493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 1105d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 1106d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 1107694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onCancelEvent(final int x, final int y, final long eventTime) { 1108694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1109dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 1110694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 11111d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 111293b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime); 111393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 1114baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 11151d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 11161d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1117baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 11182321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1119e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 1120f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 11219d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 11229d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 11239d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 11249ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 11256a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11266a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1127694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startRepeatKey(final Key key) { 11286c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (key != null && key.isRepeatable() && !sInGesture) { 11296662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv onRegisterKey(key); 1130a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(this); 1131a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1132a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1133a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 1134694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onRegisterKey(final Key key) { 1135c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka if (key != null) { 11363623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis()); 1137d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 1138c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 11396a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11406a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1141b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, 1142b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final Key newKey) { 1143694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyDetector == null) { 1144a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 1145694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1146694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final Key curKey = mCurrentKey; 11476a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 1148e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 1149a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1150a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (curKey == null /* && newKey != null */) { 1151a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1152a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1153a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka // Here curKey points to the different key from newKey. 1154a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( 1155a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mIsInSlidingKeyInputFromModifier); 1156a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); 1157a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { 1158a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1159a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared) 1160a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka / mKeyboard.mMostCommonKeyWidth; 1161a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1162a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka +" %.2f key width from key edge", mPointerId, distanceToEdgeRatio)); 1163b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1164a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1165a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1166a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput 1167a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && sTimeRecorder.isInFastTyping(eventTime) 1168a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) { 1169a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1170a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 1171a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 1172a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float lengthFromDownRatio = 1173a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal; 1174a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1175a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka + " %.2f key diagonal from virtual down point", 1176a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mPointerId, lengthFromDownRatio)); 1177b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1178e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 11796a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1180a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return false; 11816a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11826a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1183694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startLongPressTimer(final Key key) { 11846c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (key != null && key.isLongPressEnabled() && !sInGesture) { 1185a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startLongPressTimer(this); 11864189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 118766e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 118866e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 11893623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) { 119083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 11918aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 1192dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 1193dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 119466e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 1195694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final int code = key.mCode; 11963623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka callListenerOnCodeInput(key, code, x, y, eventTime); 11972013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka callListenerOnRelease(key, code, false); 11986a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11996a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1200694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void printTouchEvent(final String title, final int x, final int y, 1201694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final long eventTime) { 1202723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka final Key key = mKeyDetector.detectHitKey(x, y); 1203e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka final String code = KeyDetector.printableCode(key); 120458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, 120558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka (mKeyAlreadyProcessed ? "-" : " "), title, x, y, eventTime, code)); 1206dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 12076e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 1208