PointerTracker.java revision 41016acacfa21354f59ed51db1f85ea3d99bf6a4
16a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka/* 28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 36a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License. 68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at 76a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi 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 118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and 148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under 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; 2805124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints.GestureStrokePreviewParams; 2972934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 305f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils; 31240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaokaimport com.android.inputmethod.latin.Constants; 32547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaokaimport com.android.inputmethod.latin.CoordinateUtils; 33f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 34faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 355509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport com.android.inputmethod.latin.R; 369bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 376b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 386a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 395c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 40dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 41a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class PointerTracker implements PointerTrackerQueue.Element { 42dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 43dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 44dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 45dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 46b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG || DEBUG_EVENT; 4740a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 480657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka /** True if {@link PointerTracker}s should handle gesture events. */ 490657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka private static boolean sShouldHandleGesture = false; 508335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sMainDictionaryAvailable = false; 518335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByInputField = false; 528335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByUser = false; 53918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 54f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public interface KeyEventHandler { 55f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 56f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyDetector object that is used for this PointerTracker. 57f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyDetector object that is used for this PointerTracker 58f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 59f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyDetector getKeyDetector(); 60f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 61f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 62f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyboardActionListener object that is used to register key code and so on. 63f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyboardActionListner for this PointerTracker 64f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 65f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener(); 66f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 67f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 68f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get DrawingProxy object that is used for this PointerTracker. 69f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the DrawingProxy object that is used for this PointerTracker 70f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 71f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy(); 72f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 73f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 74f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get TimerProxy object that handles key repeat and long press timer event for this 75f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * PointerTracker. 76f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the TimerProxy object that handles key repeat and long press timer event. 77f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 78f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public TimerProxy getTimerProxy(); 79f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 80f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 81fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang public interface DrawingProxy { 826a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public void invalidateKey(Key key); 83e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public void showKeyPreview(PointerTracker tracker); 84d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void dismissKeyPreview(PointerTracker tracker); 85547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void showSlidingKeyInputPreview(PointerTracker tracker); 8608d8a676c28f30a722629cb4713177064f6422e2Tadashi G. Takaoka public void dismissSlidingKeyInputPreview(); 87cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa public void showGestureTrail(PointerTracker tracker); 886a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 896a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 902321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public interface TimerProxy { 91d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey); 9273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState(); 93a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker); 94a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker); 95a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code); 9698b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer(); 970ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer(); 98beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer(); 990ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout(); 1002321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelKeyTimers(); 10172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(PointerTracker tracker); 102915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka public void cancelUpdateBatchInputTimer(PointerTracker tracker); 1032db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers(); 10429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 10529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static class Adapter implements TimerProxy { 10629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 107d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey) {} 10893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 10973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { return false; } 11093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 111a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker) {} 11229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 113a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker) {} 114a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 115a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code) {} 11629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 11729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelLongPressTimer() {} 11829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 1190ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer() {} 1200ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 121beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer() {} 122beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 1230ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout() { return false; } 1240ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 12529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelKeyTimers() {} 12672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 12772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(PointerTracker tracker) {} 12872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 129915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka public void cancelUpdateBatchInputTimer(PointerTracker tracker) {} 130915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka @Override 1312db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers() {} 13229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 1332321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka } 1342321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka 135a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka static final class PointerTrackerParams { 1365509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final boolean mSlidingKeyInputEnabled; 1375509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final int mTouchNoiseThresholdTime; 138b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public final int mTouchNoiseThresholdDistance; 1393623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public final int mSuppressKeyPreviewAfterBatchInputDuration; 1405509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1415509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); 1425509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1435509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private PointerTrackerParams() { 1445509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = false; 1455509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = 0; 146b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = 0; 1473623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 0; 1485509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1495509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 15080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) { 1515509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean( 1525509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_slidingKeyInputEnable, false); 1535509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( 1545509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); 155b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( 1565509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); 1573623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt( 1583623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0); 1595509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1605509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1615509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 162160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka // Parameters for pointer handling. 1635509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private static PointerTrackerParams sParams; 16480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private static GestureStrokeParams sGestureStrokeParams; 16505124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaoka private static GestureStrokePreviewParams sGesturePreviewParams; 166d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka private static boolean sNeedsPhantomSuddenMoveEventHack; 167b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move this threshold to resource. 168b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // TODO: Device specific parameter would be better for device specific hack? 169b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth 170b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // This hack might be device specific. 171b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final boolean sNeedsProximateBogusDownMoveUpEventHack = true; 1725c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1735f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); 17493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue(); 1755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1765c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 1776a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1780efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 1790efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 180a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 18184ac8f31fbe30f03c14a85ffb8c827edb6e47ab0Tadashi G. Takaoka private KeyboardActionListener mListener = KeyboardActionListener.Adapter.EMPTY_LISTENER; 182baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1835a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 184b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mPhantonSuddenMoveThreshold; 185b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); 1866a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1876c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private boolean mIsDetectingGesture = false; // per PointerTracker. 1886c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static boolean sInGesture = false; 1896c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static long sGestureFirstDownTime; 1903623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private static TimeRecorder sTimeRecorder; 1916c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static final InputPointers sAggregratedPointers = new InputPointers( 1926c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka GestureStroke.DEFAULT_CAPACITY); 19358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers 19458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers 1959580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 196b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static final class BogusMoveEventDetector { 197b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move these thresholds to resource. 198d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // These thresholds' unit is a diagonal length of a key. 199d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f; 200d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f; 201b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 202b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mAccumulatedDistanceThreshold; 203b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mRadiusThreshold; 204b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 205b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Accumulated distance from actual and artificial down keys. 206b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int mAccumulatedDistanceFromDownKey; 207b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownX; 208b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownY; 209b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 210d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public void setKeyboardGeometry(final int keyWidth, final int keyHeight) { 211d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight); 212b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceThreshold = (int)( 213d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); 214d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD); 215b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 216b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 217b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onActualDownEvent(final int x, final int y) { 218b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownX = x; 219b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownY = y; 220b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 221b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 222b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onDownKey() { 223b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey = 0; 224b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 225b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 226b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onMoveKey(final int distance) { 227b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey += distance; 228b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 229b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 230d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public boolean hasTraveledLongDistance(final int x, final int y) { 231d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dx = Math.abs(x - mActualDownX); 232d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dy = Math.abs(y - mActualDownY); 233d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // A bogus move event should be a horizontal movement. A vertical movement might be 234d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // a sloppy typing and should be ignored. 235d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; 236b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 237b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 238b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int getDistanceFromDownEvent(final int x, final int y) { 239b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistance(x, y, mActualDownX, mActualDownY); 240b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 241b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 242b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isCloseToActualDownEvent(final int x, final int y) { 243b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistanceFromDownEvent(x, y) < mRadiusThreshold; 244b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 245b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 246b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2473623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka static final class TimeRecorder { 2483623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mSuppressKeyPreviewAfterBatchInputDuration; 2493623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mStaticTimeThresholdAfterFastTyping; // msec 2503623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastTypingTime; 2513623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastLetterTypingTime; 2523623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastBatchInputTime; 2533623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2543623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public TimeRecorder(final PointerTrackerParams pointerTrackerParams, 2553623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final GestureStrokeParams gestureStrokeParams) { 2563623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 2573623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka pointerTrackerParams.mSuppressKeyPreviewAfterBatchInputDuration; 2583623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = 2593623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka gestureStrokeParams.mStaticTimeThresholdAfterFastTyping; 2603623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2613623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 262b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isInFastTyping(final long eventTime) { 263b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; 264b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; 265b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 266b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2677a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka private boolean wasLastInputTyping() { 2687a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return mLastTypingTime >= mLastBatchInputTime; 2693623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2703623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2713623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onCodeInput(final int code, final long eventTime) { 2727a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // Record the letter typing time when 2737a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 1. Letter keys are typed successively without any batch input in between. 2747a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 2. A letter key is typed within the threshold time since the last any key typing. 2757a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 3. A non-letter key is typed within the threshold time since the last letter key 2767a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // typing. 2777a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (Character.isLetter(code)) { 2787a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (wasLastInputTyping() 2797a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) { 2807a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2813623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2823623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } else { 2833623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) { 2843623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // This non-letter typing should be treated as a part of fast typing. 2857a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2863623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2873623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2887a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastTypingTime = eventTime; 2893623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2903623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2913623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onEndBatchInput(final long eventTime) { 2927a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastBatchInputTime = eventTime; 2933623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2943623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2953623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public long getLastLetterTypingTime() { 2963623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return mLastLetterTypingTime; 2973623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2983623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2993623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 3007a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return !wasLastInputTyping() 3013623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration; 3023623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3033623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3043623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 3058a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 3068a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 307547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka private int[] mDownCoordinates = CoordinateUtils.newInstance(); 3088a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 3098a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 310e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The current key where this pointer is. 311e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mCurrentKey = null; 312e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The position where the current key was recognized for the first time. 3138a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 3148a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 3158a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3168a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 3178a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 3188a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 3196a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3201a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 3211a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 3221a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 32313d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // true if this pointer is no longer triggering any action because it has been canceled. 32413d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka private boolean mIsTrackingForActionDisabled; 325c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 32635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang // the more keys panel currently being shown. equals null if no panel is active. 32735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private MoreKeysPanel mMoreKeysPanel; 3289ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 329f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input. 3305c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 331f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input from a modifier key, 332f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // so that further modifier keys should be ignored. 333f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka boolean mIsInSlidingKeyInputFromModifier; 334cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 335f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if a sliding key input is allowed. 33667a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 33767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 338c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; 339f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 34093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka public static void init(final boolean needsPhantomSuddenMoveEventHack) { 341d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack; 3425509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = PointerTrackerParams.DEFAULT; 34380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = GestureStrokeParams.DEFAULT; 34405124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaoka sGesturePreviewParams = GestureStrokePreviewParams.DEFAULT; 3453623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 346160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 34793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3485509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static void setParameters(final TypedArray mainKeyboardViewAttr) { 3495509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = new PointerTrackerParams(mainKeyboardViewAttr); 35080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr); 35105124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaoka sGesturePreviewParams = new GestureStrokePreviewParams(mainKeyboardViewAttr); 3523623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 3536a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3546a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3558335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static void updateGestureHandlingMode() { 3568335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sShouldHandleGesture = sMainDictionaryAvailable 3578335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByInputField 3588335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByUser 3598335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); 3608335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 3618335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 3628335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 363694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 3648335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sMainDictionaryAvailable = mainDictionaryAvailable; 3658335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 3668335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 3678335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 368694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 3698335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; 3708335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 371918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka } 372918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 373694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, final KeyEventHandler handler) { 374b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka final ArrayList<PointerTracker> trackers = sTrackers; 3755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3765c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 3775c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 3785c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 3795c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 3805c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3825c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 3835c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3845c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3855c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 38693b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.isAnyInSlidingKeyInput(); 3875c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 389694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyboardActionListener(final KeyboardActionListener listener) { 390afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 391afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 392afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 3935c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 3945c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3965c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 397694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyDetector(final KeyDetector keyDetector) { 398afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 399afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 400afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 4015c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 4025c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 4035c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 4045c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 405918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 4068335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput(); 4078335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 4085c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4095c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 410dde36ef34329164cf8b8a3985c578dab0343b3ebTadashi G. Takaoka public static void setReleasedKeyGraphicsToAllKeys() { 411afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 412afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 413afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 414e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.mCurrentKey); 4155c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4165c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4175c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 418ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang public static void dismissAllMoreKeysPanels() { 419ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final int trackersSize = sTrackers.size(); 420ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang for (int i = 0; i < trackersSize; ++i) { 421ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final PointerTracker tracker = sTrackers.get(i); 422ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (tracker.isShowingMoreKeysPanel()) { 423ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang tracker.mMoreKeysPanel.dismissMoreKeysPanel(); 424ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang tracker.mMoreKeysPanel = null; 425ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 426ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 427ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 428ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 429694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private PointerTracker(final int id, final KeyEventHandler handler) { 430694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (handler == null) { 4315c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 432694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 4335c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 43480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints( 43505124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaoka id, sGestureStrokeParams, sGesturePreviewParams); 4365c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 4375c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 4385c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 4395c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 4406a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4416a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 4421a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 443694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key) { 44413d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // While gesture input is going on, this method should be a no-operation. But when gesture 44513d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // input has been canceled, <code>sInGesture</code> and <code>mIsDetectingGesture</code> 44613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // are set to false. To keep this method is a no-operation, 44713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // <code>mIsTrackingForActionDisabled</code> should also be taken account of. 44813d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (sInGesture || mIsDetectingGesture || mIsTrackingForActionDisabled) { 449eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return false; 450eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 4518dfbb740e1015af0cd339a183dd333a5f53c52c4Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); 452e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 45358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId, 45458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka KeyDetector.printableCode(key), 45558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka ignoreModifierKey ? " ignoreModifier" : "", 45658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "" : " disabled")); 457e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 45893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (ignoreModifierKey) { 459996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 46093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 461e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 46241016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka mListener.onPressKey(key.mCode, getActivePointerTrackerCount() == 1); 463690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 464690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 465d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 466690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 467690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 468690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 469dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 470dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 471690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 472690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 473694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, 4743623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final int y, final long eventTime) { 4758dfbb740e1015af0cd339a183dd333a5f53c52c4Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); 4766bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 47729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int code = altersCode ? key.getAltCode() : primaryCode; 4782013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (DEBUG_LISTENER) { 479240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final String output = code == Constants.CODE_OUTPUT_TEXT 480240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka ? key.getOutputText() : Constants.printableCode(code); 48158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y, 48258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka output, ignoreModifierKey ? " ignoreModifier" : "", 48358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled")); 4842013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4859c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 4869bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, 4879bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge altersCode, code); 4889bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 489e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 490996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 491e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 4926bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 4936bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.isEnabled() || altersCode) { 4943623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onCodeInput(code, eventTime); 495240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (code == Constants.CODE_OUTPUT_TEXT) { 49629d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka mListener.onTextInput(key.getOutputText()); 497240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (code != Constants.CODE_UNSPECIFIED) { 498ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mListener.onCodeInput(code, x, y); 4992013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 50093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 501dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 502dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 503f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may be in shifted state and the 504690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 505694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnRelease(final Key key, final int primaryCode, 506694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final boolean withSliding) { 50713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // See the comment at {@link #callListenerOnPressAndCheckKeyboardLayoutChange(Key}}. 50813d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (sInGesture || mIsDetectingGesture || mIsTrackingForActionDisabled) { 509eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 510eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 5118dfbb740e1015af0cd339a183dd333a5f53c52c4Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); 512e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 51358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, 514240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka Constants.printableCode(primaryCode), 51558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "", 51658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "": " disabled")); 517e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 5189c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 5199bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, 5209bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ignoreModifierKey); 5219bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 522e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 523996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 524e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 52593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (key.isEnabled()) { 5262a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onReleaseKey(primaryCode, withSliding); 52793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 528dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 529dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 53041016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka private void callListenerOnFinishSlidingInput() { 53141016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka if (DEBUG_LISTENER) { 53241016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onFinishSlidingInput", mPointerId)); 53341016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 53441016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka mListener.onFinishSlidingInput(); 53541016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 53641016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka 5378aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 538694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_LISTENER) { 53958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelInput", mPointerId)); 540694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 5419c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 5429bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCancelInput(); 5439bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 5448aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 545dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 546dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 547694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setKeyDetectorInner(final KeyDetector keyDetector) { 54858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 54958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (keyDetector == mKeyDetector && keyboard == mKeyboard) { 55058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return; 55158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 552a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 5535a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 554d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyWidth = mKeyboard.mMostCommonKeyWidth; 555d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyHeight = mKeyboard.mMostCommonKeyHeight; 556b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); 5578a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); 5588a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (newKey != mCurrentKey) { 5598a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (mDrawingProxy != null) { 5608a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 5618a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 56244972bcdb6f6dd0e4f02a26f31c7effaf0525403Tadashi G. Takaoka // Keep {@link #mCurrentKey} that comes from previous keyboard. 5638a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 564b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); 565d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mBogusMoveEventDetector.setKeyboardGeometry(keyWidth, keyHeight); 5665a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 5675a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 5680cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 569cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 570cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 571cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 572cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 573547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public boolean isInSlidingKeyInputFromModifier() { 574547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka return mIsInSlidingKeyInputFromModifier; 575547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka } 576547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka 577e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKey() { 578e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey; 579dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 580dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 5810cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 5822aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 583e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey != null && mCurrentKey.isModifier(); 5842aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 5852aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 586694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public Key getKeyOn(final int x, final int y) { 587723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 5882aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 5892aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 590694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setReleasedKeyGraphics(final Key key) { 591d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 5926bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 593faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 594faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 595faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 5966bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, update the key release graphics just in case. 597faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(key); 598faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 599faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 600faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 601faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 602faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(shiftKey); 6032013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6042013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 605faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 6062013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 607faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.altCodeWhileTyping()) { 60829d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 609faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 610faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 611faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(altKey); 612faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 613faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 61429d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 615faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(k); 6162013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6172013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6196a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6206a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 62129d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 62229d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!sShouldHandleGesture) return false; 6233623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime); 62429d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka } 62529d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka 62629d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void setPressedKeyGraphics(final Key key, final long eventTime) { 6276bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 6286bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka return; 6296bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 6306bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka 6316bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 6326bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 6336bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; 6346bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (!needsToUpdateGraphics) { 635faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 636faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 637faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 63829d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!key.noKeyPreview() && !sInGesture && !needsToSuppressKeyPreviewPopup(eventTime)) { 639faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.showKeyPreview(this); 640faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 641faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(key); 642faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 643faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 644faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 645faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 646faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(shiftKey); 6472013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6482013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 649faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 6502013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 65173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) { 65229d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 653faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 654faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 655faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(altKey); 656faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 657faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 65829d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 659faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(k); 6602013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6612013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 662d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 663c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 664c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 665694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updateReleaseKeyGraphics(final Key key) { 666faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onReleased(); 667faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 668faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 669faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 670694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updatePressKeyGraphics(final Key key) { 671faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onPressed(); 672faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 673faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 674faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 675c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { 676c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka return mGestureStrokeWithPreviewPoints; 6772f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 6782f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang 679547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void getLastCoordinates(final int[] outCoords) { 680547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.set(outCoords, mLastX, mLastY); 6818a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6828a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 6838a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 6848a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 6858a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6868a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 687547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void getDownCoordinates(final int[] outCoords) { 688547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.copy(outCoords, mDownCoordinates); 689547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka } 690547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka 691694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onDownKey(final int x, final int y, final long eventTime) { 6928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 693547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.set(mDownCoordinates, x, y); 694b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onDownKey(); 6958a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 6968a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6978a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 698b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static int getDistance(final int x1, final int y1, final int x2, final int y2) { 699b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return (int)Math.hypot(x1 - x2, y1 - y2); 700b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 701b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 702694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKeyInternal(final int x, final int y) { 703b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onMoveKey(getDistance(x, y, mLastX, mLastY)); 7048a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 7058a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 706723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 7078a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7088a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 709694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKey(final int x, final int y) { 7108a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 7118a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7128a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 713694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveToNewKey(final Key newKey, final int x, final int y) { 714e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mCurrentKey = newKey; 7158a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 7168a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 717e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return newKey; 7188a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7198a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 7206c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static int getActivePointerTrackerCount() { 72193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.size(); 7226c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7236c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 724ab334eb64669e909f0a401fddffa891962002602Tadashi G. Takaoka public boolean isOldestTrackerInQueue() { 725ab334eb64669e909f0a401fddffa891962002602Tadashi G. Takaoka return sPointerTrackerQueue.getOldestElement() == this; 72613ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka } 72713ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka 7281645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka private void mayStartBatchInput(final Key key) { 729c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { 7309c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka return; 7319c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka } 7321645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka if (key == null || !Character.isLetter(key.mCode)) { 7331645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka return; 7341645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka } 7359c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka if (DEBUG_LISTENER) { 73658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); 7379580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7389c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka sInGesture = true; 73958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka synchronized (sAggregratedPointers) { 74058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sAggregratedPointers.reset(); 74158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionPointSize = 0; 74258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionTime = 0; 74358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mListener.onStartBatchInput(); 744ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang dismissAllMoreKeysPanels(); 74558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 746ad181915f78235bc09e88c85ed9df669801b8442Tadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 747cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa mDrawingProxy.showGestureTrail(this); 7486c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7496c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 75072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void updateBatchInputByTimer(final long eventTime) { 75172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 75272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.duplicateLastPointWith(gestureTime); 75372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka updateBatchInput(eventTime); 75472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 75572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 756157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka private void mayUpdateBatchInput(final long eventTime, final Key key) { 757157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (key != null) { 75872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka updateBatchInput(eventTime); 75972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 76013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 7616f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka return; 7626f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka } 763cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa mDrawingProxy.showGestureTrail(this); 76472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 76572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 76672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private void updateBatchInput(final long eventTime) { 76772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka synchronized (sAggregratedPointers) { 76872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final GestureStroke stroke = mGestureStrokeWithPreviewPoints; 76972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka stroke.appendIncrementalBatchPoints(sAggregratedPointers); 77072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int size = sAggregratedPointers.getPointerSize(); 77172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (size > sLastRecognitionPointSize 77272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) { 77372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka sLastRecognitionPointSize = size; 77472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka sLastRecognitionTime = eventTime; 77572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (DEBUG_LISTENER) { 77672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, 77772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka size)); 7786c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 77972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mTimerProxy.startUpdateBatchInputTimer(this); 78072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mListener.onUpdateBatchInput(sAggregratedPointers); 7816c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7829580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7839580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7849580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 78529d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void mayEndBatchInput(final long eventTime) { 7866c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka synchronized (sAggregratedPointers) { 787c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); 7886c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 7896c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sInGesture = false; 7903623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onEndBatchInput(eventTime); 791b5fc0e02d04550d39bfa98c2dde805f1c1d3f9a3Tadashi G. Takaoka mTimerProxy.cancelAllUpdateBatchInputTimers(); 79213d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (!mIsTrackingForActionDisabled) { 793b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (DEBUG_LISTENER) { 794b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", 795b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mPointerId, sAggregratedPointers.getPointerSize())); 796b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 797b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mListener.onEndBatchInput(sAggregratedPointers); 798b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 7996c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8009580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 80113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 8026f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka return; 8036f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka } 804cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa mDrawingProxy.showGestureTrail(this); 8059580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8069580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 8078e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka private void cancelBatchInput() { 8088e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sPointerTrackerQueue.cancelAllPointerTracker(); 8098353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka mIsDetectingGesture = false; 8107c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka if (!sInGesture) { 8117c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka return; 8127c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka } 8138e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sInGesture = false; 8148e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka if (DEBUG_LISTENER) { 8158e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelBatchInput", mPointerId)); 8168e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } 8178e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka mListener.onCancelBatchInput(); 8188e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } 8198e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka 820694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void processMotionEvent(final int action, final int x, final int y, final long eventTime, 821694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 8228ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka switch (action) { 8238ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 8248ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 8258ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onDownEvent(x, y, eventTime, handler); 8268ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8278ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_UP: 8288ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 8298ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onUpEvent(x, y, eventTime); 8308ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8318ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 8323314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka onMoveEvent(x, y, eventTime, null); 8338ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8348ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 8358ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onCancelEvent(x, y, eventTime); 8368ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8378ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 8388ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 8398ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 840694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onDownEvent(final int x, final int y, final long eventTime, 841694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 842694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 843dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 844694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 845f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 84663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 847f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyboardActionListener(handler.getKeyboardActionListener()); 848f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 849baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 8508a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 851160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka if (deltaT < sParams.mTouchNoiseThresholdTime) { 852b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final int distance = getDistance(x, y, mLastX, mLastY); 853b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (distance < sParams.mTouchNoiseThresholdDistance) { 854faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 855b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onDownEvent:" 856b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " ignore potential noise: time=%d distance=%d", 857b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, deltaT, distance)); 8589c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 859b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance); 8609bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 86113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 862baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 863baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 864baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 865baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 866eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final Key key = getKeyOn(x, y); 867b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onActualDownEvent(x, y); 86893b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (key != null && key.isModifier()) { 86993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 87093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 87193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 8721d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 87393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.add(this); 8741d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 8756c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!sShouldHandleGesture) { 8766c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 8776c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8784df6549c1a5ae2cdc2cdfafdad1ec2a75881134cTadashi G. Takaoka // A gesture should start only from a non-modifier key. 879b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() 880ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang && key != null && !key.isModifier(); 881b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (mIsDetectingGesture) { 882b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 8836c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sGestureFirstDownTime = eventTime; 8849580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 88558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime, 8863623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.getLastLetterTypingTime()); 887eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 8881d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8891d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 89035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private boolean isShowingMoreKeysPanel() { 89135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return (mMoreKeysPanel != null); 89235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 89335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 894694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void onDownEventInternal(final int x, final int y, final long eventTime) { 895e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onDownKey(x, y, eventTime); 89667a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 89732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. 898160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mIsAllowedSlidingKeyInput = sParams.mSlidingKeyInputEnabled 899c9f203805ca23276fcdcdc79b9298bc1d413ad98Tadashi G. Takaoka || (key != null && key.isModifier()) 90032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka || mKeyDetector.alwaysAllowsSlidingInput(); 9011a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 90213d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka mIsTrackingForActionDisabled = false; 903f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 904e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 9051a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 906e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the new 9071a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 9082a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 909e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onDownKey(x, y, eventTime); 910e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 911996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 912e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 913e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 91429d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 9156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9176a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 918694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startSlidingKeyInput(final Key key) { 919e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (!mIsInSlidingKeyInput) { 920f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = key.isModifier(); 921e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 922996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 923996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 924996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 925f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka private void resetSlidingKeyInput() { 926f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInput = false; 927f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = false; 92808d8a676c28f30a722629cb4713177064f6422e2Tadashi G. Takaoka mDrawingProxy.dismissSlidingKeyInputPreview(); 929f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka } 930f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka 9316c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onGestureMoveEvent(final int x, final int y, final long eventTime, 93202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final boolean isMajorEvent, final Key key) { 9336c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 9346c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (mIsDetectingGesture) { 935b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka final int beforeLength = mGestureStrokeWithPreviewPoints.getLength(); 936b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka final boolean onValidArea = mGestureStrokeWithPreviewPoints.addPointOnKeyboard( 937b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka x, y, gestureTime, isMajorEvent); 938b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka if (mGestureStrokeWithPreviewPoints.getLength() > beforeLength) { 939b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka mTimerProxy.startUpdateBatchInputTimer(this); 940b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka } 9418353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka // If the move event goes out from valid batch input area, cancel batch input. 942b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (!onValidArea) { 9438e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka cancelBatchInput(); 944b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka return; 945b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 946ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang // If the MoreKeysPanel is showing then do not attempt to enter gesture mode. However, 947ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang // the gestured touch points are still being recorded in case the panel is dismissed. 948ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 949ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang return; 950ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 9511645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka mayStartBatchInput(key); 952157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (sInGesture) { 953157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mayUpdateBatchInput(eventTime, key); 9549580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 9559580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 9569580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 9579580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 958694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) { 959694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_MOVE_EVENT) { 960dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 961694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 96213d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 963e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 964694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 965baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 9666c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture && me != null) { 967eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Add historical points to gesture path. 968eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int pointerIndex = me.findPointerIndex(mPointerId); 969eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalSize = me.getHistorySize(); 970eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int h = 0; h < historicalSize; h++) { 971eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalX = (int)me.getHistoricalX(pointerIndex, h); 972eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalY = (int)me.getHistoricalY(pointerIndex, h); 973eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final long historicalTime = me.getHistoricalEventTime(h); 9746c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onGestureMoveEvent(historicalX, historicalY, historicalTime, 97502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka false /* isMajorEvent */, null); 976eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 977eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 978ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 979ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 980ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka final int translatedX = mMoreKeysPanel.translateX(x); 981ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka final int translatedY = mMoreKeysPanel.translateY(y); 982ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime); 983ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka onMoveKey(x, y); 984ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mDrawingProxy.showSlidingKeyInputPreview(this); 985ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang return; 986ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 9876c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onMoveEventInternal(x, y, eventTime); 9886c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 9896c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 9903c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processSlidingKeyInput(final Key newKey, final int x, final int y, 9913c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime) { 9923c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 9933c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update key according 9943c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // to the new keyboard layout. 9953c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Key key = newKey; 9963c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 9973c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka key = onMoveKey(x, y); 9983c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 9993c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onMoveToNewKey(key, x, y); 100013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 100113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka return; 100213d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka } 10033c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka startLongPressTimer(key); 10043c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 10053c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10063c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 10073c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processPhantomSuddenMoveHack(final Key key, final int x, final int y, 10083c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 10093c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 10103c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 10113c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " phantom sudden move event (distance=%d) is translated to " 10123c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, 10133c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka getDistance(x, y, lastX, lastY), 10143c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.mCode), 10153c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka x, y, Constants.printableCode(key.mCode))); 10163c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10173c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // TODO: This should be moved to outside of this nested if-clause? 10189c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 10193c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); 10203c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 102135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 10223c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 10233c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10243c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 10253c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processProximateBogusDownMoveUpEventHack(final Key key, final int x, final int y, 10263c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 10273c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 10283c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 10293c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 10303c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float radiusRatio = 10313c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mBogusMoveEventDetector.getDistanceFromDownEvent(x, y) 10323c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka / keyDiagonal; 10333c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 10343c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " bogus down-move-up event (raidus=%.2f key diagonal) is " 10353c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " translated to up[%d,%d,%s]/down[%d,%d,%s] events", 10363c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mPointerId, radiusRatio, 10373c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.mCode), 10383c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka x, y, Constants.printableCode(key.mCode))); 10393c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 104035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 10413c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 10423c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10433c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 1044831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka private void processSildeOutFromOldKey(final Key oldKey) { 1045831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 104641016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true /* withSliding */); 1047831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka startSlidingKeyInput(oldKey); 1048831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1049831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } 1050831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka 10513c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void slideFromOldKeyToNewKey(final Key key, final int x, final int y, 10528b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 10538b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 10548b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 10558b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onPress() to notify that the new key is being pressed. 1056831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSildeOutFromOldKey(oldKey); 10578b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka startRepeatKey(key); 10588b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 10593c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka processSlidingKeyInput(key, x, y, eventTime); 10602a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 10612a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be reported as a sudden move by 10622a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // touch panel firmware. This hack detects such cases and translates the move event to 10632a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // successive up and down events. 10642a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // TODO: Should find a way to balance gesture detection and this hack. 10652a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsPhantomSuddenMoveEventHack 10662a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) { 10672a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processPhantomSuddenMoveHack(key, x, y, eventTime, oldKey, lastX, lastY); 10682a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 10692a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive proximate touches may be reported as a bogus 10702a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // down-move-up event by touch panel firmware. This hack detects such cases and breaks 10712a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // these events into separate up and down events. 10722a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsProximateBogusDownMoveUpEventHack && sTimeRecorder.isInFastTyping(eventTime) 10732a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { 10742a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY); 10752a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 10762a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: If there are currently multiple touches, register the key even if the finger 10772a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // slides off the key. This defends against noise from some touch panels when there are 10782a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // close multiple touches. 10792a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // Caveat: When in chording input mode with a modifier key, we don't use this hack. 108093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka else if (getActivePointerTrackerCount() > 1 10812a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { 10822a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (DEBUG_MODE) { 10832a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 10842a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka + " detected sliding finger while multi touching", mPointerId)); 10853c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10862a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka onUpEvent(x, y, eventTime); 108713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 10882a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka setReleasedKeyGraphics(oldKey); 10892a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } else { 10902a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (!mIsDetectingGesture) { 109113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 10928b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10932a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka setReleasedKeyGraphics(oldKey); 10948b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10958b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 10968b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 10978b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka private void slideOutFromOldKey(final Key oldKey, final int x, final int y) { 10988b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 10998b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // notify that the previous key has been released. 1100831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSildeOutFromOldKey(oldKey); 11018b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 11028b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onMoveToNewKey(null, x, y); 11038b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } else { 11048b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (!mIsDetectingGesture) { 110513d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 11068b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11078b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11088b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11098b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 11106c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onMoveEventInternal(final int x, final int y, final long eventTime) { 11118a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 11128a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 1113e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key oldKey = mCurrentKey; 11148b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final Key newKey = onMoveKey(x, y); 1115eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 11166c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture) { 11176c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // Register move event on gesture tracker. 11188b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey); 11196c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 11206c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 11216c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 11226c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 11236c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 1124eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1125eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 11268b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (newKey != null) { 11273c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 11288b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka slideFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY); 11293c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } else if (oldKey == null) { 1130831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 1131831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 1132831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSlidingKeyInput(newKey, x, y, eventTime); 1133c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 1134831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } else { // newKey == null 11358b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 11368b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka slideOutFromOldKey(oldKey, x, y); 113707221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 11386a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1139547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka mDrawingProxy.showSlidingKeyInputPreview(this); 11406a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11416a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1142694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onUpEvent(final int x, final int y, final long eventTime) { 1143694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1144dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 1145694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 11461d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1147915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka mTimerProxy.cancelUpdateBatchInputTimer(this); 114893b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (!sInGesture) { 114993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (mCurrentKey != null && mCurrentKey.isModifier()) { 115093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing an up event of modifier key, all pointers already being 115193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 115293b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime); 115393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka } else { 115493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime); 11551d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 11561d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 115735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 115893b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 11591d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 11601d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1161d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 1162d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 1163d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 11640cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 1165694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onPhantomUpEvent(final long eventTime) { 1166694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1167547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka printTouchEvent("onPhntEvent:", mLastX, mLastY, eventTime); 1168694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 116935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (isShowingMoreKeysPanel()) { 117035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return; 117135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 117235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(mLastX, mLastY, eventTime); 117313d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 11741d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 11751d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 117635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private void onUpEventInternal(final int x, final int y, final long eventTime) { 11772321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1178e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka final boolean isInSlidingKeyInput = mIsInSlidingKeyInput; 117941016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka final boolean isInSlidingKeyInputFromModifier = mIsInSlidingKeyInputFromModifier; 1180f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 11816c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIsDetectingGesture = false; 11826c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final Key currentKey = mCurrentKey; 11836c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 11845a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka // Release the last pressed key. 11856c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(currentKey); 118635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 118735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (isShowingMoreKeysPanel()) { 118813d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (!mIsTrackingForActionDisabled) { 118935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedX = mMoreKeysPanel.translateX(x); 119035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedY = mMoreKeysPanel.translateY(y); 119135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.onUpEvent(translatedX, translatedY, mPointerId, eventTime); 119235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 119335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.dismissMoreKeysPanel(); 119435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel = null; 119535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return; 11969ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 1197eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 11986c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 11996c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null) { 120041016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka callListenerOnRelease(currentKey, currentKey.mCode, true /* withSliding */); 1201eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 120229d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka mayEndBatchInput(eventTime); 1203eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 1204eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 120558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 120613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 1207d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 1208694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1209e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka if (currentKey != null && currentKey.isRepeatable() && !isInSlidingKeyInput) { 1210e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka // Repeatable key has been registered in {@link #onDownEventInternal(int,int,long)}. 1211e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka return; 12126a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1213e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime); 121441016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka if (isInSlidingKeyInputFromModifier) { 121541016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka callListenerOnFinishSlidingInput(); 121641016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 12176a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 121935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang public void onShowMoreKeysPanel(final int translatedX, final int translatedY, 122035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final MoreKeysPanel panel) { 122135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang setReleasedKeyGraphics(mCurrentKey); 122235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final long eventTime = SystemClock.uptimeMillis(); 122335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel = panel; 122435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.onDownEvent(translatedX, translatedY, mPointerId, eventTime); 12259ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 12269ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 1227b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka @Override 122813d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka public void cancelTrackingForAction() { 12298353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka if (isShowingMoreKeysPanel()) { 12308353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka return; 12318353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka } 123213d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka mIsTrackingForActionDisabled = true; 1233b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1234b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 1235906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 1236547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka resetSlidingKeyInput(); 123713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 1238e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 123993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 1240d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 1241d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 1242694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onCancelEvent(final int x, final int y, final long eventTime) { 1243694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1244dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 1245694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 12461d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 12477c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka cancelBatchInput(); 12488e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sPointerTrackerQueue.cancelAllPointerTracker(); 12498e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 1250baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 12511d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 12521d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1253baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 12542321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1255e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 1256f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 1257ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 1258ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang mMoreKeysPanel.dismissMoreKeysPanel(); 1259ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang mMoreKeysPanel = null; 1260ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 12616a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12626a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1263694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startRepeatKey(final Key key) { 1264ad662adeef10c4b202f8f5f80037dd5b8fc9583dTadashi G. Takaoka if (sInGesture) return; 1265ad662adeef10c4b202f8f5f80037dd5b8fc9583dTadashi G. Takaoka if (key == null) return; 1266ad662adeef10c4b202f8f5f80037dd5b8fc9583dTadashi G. Takaoka if (!key.isRepeatable()) return; 1267ad662adeef10c4b202f8f5f80037dd5b8fc9583dTadashi G. Takaoka // Don't start key repeat when we are in sliding input mode. 1268e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka if (mIsInSlidingKeyInput) return; 1269ad662adeef10c4b202f8f5f80037dd5b8fc9583dTadashi G. Takaoka onRegisterKey(key); 1270ad662adeef10c4b202f8f5f80037dd5b8fc9583dTadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(this); 1271a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1272a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 1273694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onRegisterKey(final Key key) { 1274c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka if (key != null) { 12753623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis()); 1276d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 1277c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 12786a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12796a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1280b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, 1281b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final Key newKey) { 1282694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyDetector == null) { 1283a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 1284694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1285694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final Key curKey = mCurrentKey; 12866a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 1287e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 1288a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1289a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (curKey == null /* && newKey != null */) { 1290a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1291a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1292a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka // Here curKey points to the different key from newKey. 1293a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( 1294a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mIsInSlidingKeyInputFromModifier); 1295a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); 1296a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { 1297a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1298a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared) 1299a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka / mKeyboard.mMostCommonKeyWidth; 1300a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1301a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka +" %.2f key width from key edge", mPointerId, distanceToEdgeRatio)); 1302b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1303a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1304a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1305a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput 1306a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && sTimeRecorder.isInFastTyping(eventTime) 1307a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) { 1308a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1309a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 1310a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 1311a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float lengthFromDownRatio = 1312a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal; 1313a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1314a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka + " %.2f key diagonal from virtual down point", 1315a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mPointerId, lengthFromDownRatio)); 1316b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1317e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 13186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1319a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return false; 13206a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 13216a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1322694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startLongPressTimer(final Key key) { 132343ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (sInGesture) return; 132443ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (key == null) return; 132543ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (!key.isLongPressEnabled()) return; 132643ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // Caveat: Please note that isLongPressEnabled() can be true even if the current key 132743ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // doesn't have its more keys. (e.g. spacebar, globe key) 132843ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // We always need to start the long press timer if the key has its more keys regardless of 132943ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // whether or not we are in the sliding input mode. 1330e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka if (mIsInSlidingKeyInput && key.mMoreKeys == null) return; 133143ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka mTimerProxy.startLongPressTimer(this); 133266e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 133366e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 13343623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) { 133583e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 13368aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 1337dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 1338dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 133966e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 1340694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final int code = key.mCode; 13413623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka callListenerOnCodeInput(key, code, x, y, eventTime); 134241016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka callListenerOnRelease(key, code, false /* withSliding */); 13436a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 13446a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1345694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void printTouchEvent(final String title, final int x, final int y, 1346694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final long eventTime) { 1347723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka final Key key = mKeyDetector.detectHitKey(x, y); 1348e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka final String code = KeyDetector.printableCode(key); 134958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, 135013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka (mIsTrackingForActionDisabled ? "-" : " "), title, x, y, eventTime, code)); 1351dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 13526e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 1353