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 19536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaokaimport android.content.res.Resources; 205509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport android.content.res.TypedArray; 21e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaokaimport android.os.SystemClock; 22536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaokaimport android.util.DisplayMetrics; 23c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport android.util.Log; 248ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaokaimport android.view.MotionEvent; 25c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 26918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 27f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStroke; 2880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams; 29c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints; 3005124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints.GestureStrokePreviewParams; 3172934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 32240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaokaimport com.android.inputmethod.latin.Constants; 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; 37212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaokaimport com.android.inputmethod.latin.settings.Settings; 38e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils; 39e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CoordinateUtils; 40536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaokaimport com.android.inputmethod.latin.utils.ResourceUtils; 416b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 426a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 435c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 44dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 45a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class PointerTracker implements PointerTrackerQueue.Element { 46dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 47dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 48dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 49dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 50b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG || DEBUG_EVENT; 5140a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 520657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka /** True if {@link PointerTracker}s should handle gesture events. */ 530657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka private static boolean sShouldHandleGesture = false; 548335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sMainDictionaryAvailable = false; 558335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByInputField = false; 568335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByUser = false; 57918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 58f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public interface KeyEventHandler { 59f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 60f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyDetector object that is used for this PointerTracker. 61f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyDetector object that is used for this PointerTracker 62f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 63f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyDetector getKeyDetector(); 64f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 65f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 66f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyboardActionListener object that is used to register key code and so on. 67ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka * @return the KeyboardActionListner for this PointerTracke 68f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 69f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener(); 70f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 71f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 72f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get DrawingProxy object that is used for this PointerTracker. 73f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the DrawingProxy object that is used for this PointerTracker 74f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 75f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy(); 76f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 77f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 78f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get TimerProxy object that handles key repeat and long press timer event for this 79f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * PointerTracker. 80f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the TimerProxy object that handles key repeat and long press timer event. 81f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 82f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public TimerProxy getTimerProxy(); 83f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 84f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 85fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang public interface DrawingProxy { 866a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public void invalidateKey(Key key); 87e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public void showKeyPreview(PointerTracker tracker); 88d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void dismissKeyPreview(PointerTracker tracker); 89547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void showSlidingKeyInputPreview(PointerTracker tracker); 9008d8a676c28f30a722629cb4713177064f6422e2Tadashi G. Takaoka public void dismissSlidingKeyInputPreview(); 91212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public void showGestureTrail(PointerTracker tracker, boolean showsFloatingPreviewText); 926a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 936a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 942321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public interface TimerProxy { 95d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey); 9673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState(); 97ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker, int repeatCount, int delay); 98212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker, int delay); 9998b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer(); 1002a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public void startDoubleTapShiftKeyTimer(); 1012a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public void cancelDoubleTapShiftKeyTimer(); 1022a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public boolean isInDoubleTapShiftKeyTimeout(); 1032321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelKeyTimers(); 10472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(PointerTracker tracker); 105915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka public void cancelUpdateBatchInputTimer(PointerTracker tracker); 1062db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers(); 10729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 10829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static class Adapter implements TimerProxy { 10929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 110d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey) {} 11193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 11273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { return false; } 11393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 114ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker, int repeatCount, int delay) {} 11529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 116212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker, int delay) {} 117a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 11829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelLongPressTimer() {} 11929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 1202a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public void startDoubleTapShiftKeyTimer() {} 1210ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 1222a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public void cancelDoubleTapShiftKeyTimer() {} 123beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 1242a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public boolean isInDoubleTapShiftKeyTimeout() { return false; } 1250ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 12629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelKeyTimers() {} 12772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 12872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(PointerTracker tracker) {} 12972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 130915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka public void cancelUpdateBatchInputTimer(PointerTracker tracker) {} 131915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka @Override 1322db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers() {} 13329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 1342321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka } 1352321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka 136a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka static final class PointerTrackerParams { 1375509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final boolean mSlidingKeyInputEnabled; 1385509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final int mTouchNoiseThresholdTime; 139b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public final int mTouchNoiseThresholdDistance; 1403623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public final int mSuppressKeyPreviewAfterBatchInputDuration; 1418126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka public final int mKeyRepeatStartTimeout; 1428126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka public final int mKeyRepeatInterval; 143212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public final int mLongPressShiftLockTimeout; 1445509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1455509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); 1465509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1475509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private PointerTrackerParams() { 1485509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = false; 1495509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = 0; 150b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = 0; 1513623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 0; 1528126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka mKeyRepeatStartTimeout = 0; 1538126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka mKeyRepeatInterval = 0; 154212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mLongPressShiftLockTimeout = 0; 1555509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1565509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 15780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) { 1585509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean( 1595509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_slidingKeyInputEnable, false); 1605509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( 1615509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); 162b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( 1635509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); 1643623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt( 1653623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0); 1668126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt( 1678126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0); 1688126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka mKeyRepeatInterval = mainKeyboardViewAttr.getInt( 1698126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatInterval, 0); 170212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mLongPressShiftLockTimeout = mainKeyboardViewAttr.getInt( 171212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka R.styleable.MainKeyboardView_longPressShiftLockTimeout, 0); 1725509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1735509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1745509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 175160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka // Parameters for pointer handling. 1765509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private static PointerTrackerParams sParams; 17780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private static GestureStrokeParams sGestureStrokeParams; 17805124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaoka private static GestureStrokePreviewParams sGesturePreviewParams; 179d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka private static boolean sNeedsPhantomSuddenMoveEventHack; 180b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move this threshold to resource. 181b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // TODO: Device specific parameter would be better for device specific hack? 182b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth 183536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka // This hack is applied to certain classes of tablets. 184536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka // See {@link #needsProximateBogusDownMoveUpEventHack(Resources)}. 185536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka private static boolean sNeedsProximateBogusDownMoveUpEventHack; 1865c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1875f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); 18893b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue(); 1895c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 1916a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1920efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 1930efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 194a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 195f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka private KeyboardActionListener mListener = KeyboardActionListener.EMPTY_LISTENER; 196baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1975a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 198b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mPhantonSuddenMoveThreshold; 199b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); 2006a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 2016c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private boolean mIsDetectingGesture = false; // per PointerTracker. 2026c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static boolean sInGesture = false; 2036c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static long sGestureFirstDownTime; 2043623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private static TimeRecorder sTimeRecorder; 2056c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static final InputPointers sAggregratedPointers = new InputPointers( 2066c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka GestureStroke.DEFAULT_CAPACITY); 20758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers 20858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers 2099580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 210b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static final class BogusMoveEventDetector { 211b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move these thresholds to resource. 212d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // These thresholds' unit is a diagonal length of a key. 213d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f; 214d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f; 215b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 216b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mAccumulatedDistanceThreshold; 217b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mRadiusThreshold; 218b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 219b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Accumulated distance from actual and artificial down keys. 220b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int mAccumulatedDistanceFromDownKey; 221b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownX; 222b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownY; 223b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 224d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public void setKeyboardGeometry(final int keyWidth, final int keyHeight) { 225d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight); 226b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceThreshold = (int)( 227d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); 228d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD); 229b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 230b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 231b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onActualDownEvent(final int x, final int y) { 232b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownX = x; 233b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownY = y; 234b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 235b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 236b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onDownKey() { 237b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey = 0; 238b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 239b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 240b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onMoveKey(final int distance) { 241b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey += distance; 242b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 243b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 244d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public boolean hasTraveledLongDistance(final int x, final int y) { 245d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dx = Math.abs(x - mActualDownX); 246d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dy = Math.abs(y - mActualDownY); 247d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // A bogus move event should be a horizontal movement. A vertical movement might be 248d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // a sloppy typing and should be ignored. 249d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; 250b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 251b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 252b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int getDistanceFromDownEvent(final int x, final int y) { 253b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistance(x, y, mActualDownX, mActualDownY); 254b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 255b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 256b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isCloseToActualDownEvent(final int x, final int y) { 257b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistanceFromDownEvent(x, y) < mRadiusThreshold; 258b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 259b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 260b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2613623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka static final class TimeRecorder { 2623623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mSuppressKeyPreviewAfterBatchInputDuration; 2633623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mStaticTimeThresholdAfterFastTyping; // msec 2643623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastTypingTime; 2653623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastLetterTypingTime; 2663623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastBatchInputTime; 2673623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2683623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public TimeRecorder(final PointerTrackerParams pointerTrackerParams, 2693623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final GestureStrokeParams gestureStrokeParams) { 2703623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 2713623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka pointerTrackerParams.mSuppressKeyPreviewAfterBatchInputDuration; 2723623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = 2733623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka gestureStrokeParams.mStaticTimeThresholdAfterFastTyping; 2743623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2753623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 276b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isInFastTyping(final long eventTime) { 277b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; 278b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; 279b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 280b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2817a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka private boolean wasLastInputTyping() { 2827a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return mLastTypingTime >= mLastBatchInputTime; 2833623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2843623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2853623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onCodeInput(final int code, final long eventTime) { 2867a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // Record the letter typing time when 2877a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 1. Letter keys are typed successively without any batch input in between. 2887a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 2. A letter key is typed within the threshold time since the last any key typing. 2897a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 3. A non-letter key is typed within the threshold time since the last letter key 2907a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // typing. 2917a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (Character.isLetter(code)) { 2927a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (wasLastInputTyping() 2937a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) { 2947a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2953623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2963623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } else { 2973623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) { 2983623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // This non-letter typing should be treated as a part of fast typing. 2997a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 3003623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3013623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3027a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastTypingTime = eventTime; 3033623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3043623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 3053623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onEndBatchInput(final long eventTime) { 3067a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastBatchInputTime = eventTime; 3073623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3083623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 3093623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public long getLastLetterTypingTime() { 3103623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return mLastLetterTypingTime; 3113623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3123623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 3133623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 3147a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return !wasLastInputTyping() 3153623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration; 3163623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3173623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 3183623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 3198a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 3208a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 321547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka private int[] mDownCoordinates = CoordinateUtils.newInstance(); 3228a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 3238a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 324e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The current key where this pointer is. 325e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mCurrentKey = null; 326e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The position where the current key was recognized for the first time. 3278a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 3288a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 3298a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3308a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 3318a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 3328a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 3336a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3341a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 3351a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 3361a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 33713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // true if this pointer is no longer triggering any action because it has been canceled. 33813d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka private boolean mIsTrackingForActionDisabled; 339c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 34035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang // the more keys panel currently being shown. equals null if no panel is active. 34135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private MoreKeysPanel mMoreKeysPanel; 3429ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 343212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka private static final int MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT = 3; 344f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input. 3455c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 346f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input from a modifier key, 347f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // so that further modifier keys should be ignored. 348f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka boolean mIsInSlidingKeyInputFromModifier; 349a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka // if not a NOT_A_CODE, the key of this code is repeating 350a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka private int mCurrentRepeatingKeyCode = Constants.NOT_A_CODE; 351cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 352f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if a sliding key input is allowed. 35367a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 35467a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 355c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; 356f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 357536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka private static final int SMALL_TABLET_SMALLEST_WIDTH = 600; // dp 358536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka private static final int LARGE_TABLET_SMALLEST_WIDTH = 768; // dp 359536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka 360536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka private static boolean needsProximateBogusDownMoveUpEventHack(final Resources res) { 361536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka // The proximate bogus down move up event hack is needed for a device such like, 362536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka // 1) is large tablet, or 2) is small tablet and the screen density is less than hdpi. 363536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka // Though it seems odd to use screen density as criteria of the quality of the touch 364536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka // screen, the small table that has a less density screen than hdpi most likely has been 365536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka // made with the touch screen that needs the hack. 366536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka final int sw = res.getConfiguration().smallestScreenWidthDp; 367536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka final boolean isLargeTablet = (sw >= LARGE_TABLET_SMALLEST_WIDTH); 368536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka final boolean isSmallTablet = 369536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka (sw >= SMALL_TABLET_SMALLEST_WIDTH && sw < LARGE_TABLET_SMALLEST_WIDTH); 370536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka final int densityDpi = res.getDisplayMetrics().densityDpi; 371536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka final boolean hasLowDensityScreen = (densityDpi < DisplayMetrics.DENSITY_HIGH); 372536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka final boolean needsTheHack = isLargeTablet || (isSmallTablet && hasLowDensityScreen); 373536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka if (DEBUG_MODE) { 374536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka Log.d(TAG, "needsProximateBogusDownMoveUpEventHack=" + needsTheHack 375536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka + " smallestScreenWidthDp=" + sw + " densityDpi=" + densityDpi); 376536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka } 377536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka return needsTheHack; 378536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka } 379536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka 380536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka public static void init(final Resources res) { 381536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka sNeedsPhantomSuddenMoveEventHack = Boolean.parseBoolean( 382536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka ResourceUtils.getDeviceOverrideValue( 383536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka res, R.array.phantom_sudden_move_event_device_list)); 384536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka sNeedsProximateBogusDownMoveUpEventHack = needsProximateBogusDownMoveUpEventHack(res); 3855509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = PointerTrackerParams.DEFAULT; 38680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = GestureStrokeParams.DEFAULT; 38705124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaoka sGesturePreviewParams = GestureStrokePreviewParams.DEFAULT; 3883623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 389160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 39093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3915509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static void setParameters(final TypedArray mainKeyboardViewAttr) { 3925509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = new PointerTrackerParams(mainKeyboardViewAttr); 39380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr); 39405124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaoka sGesturePreviewParams = new GestureStrokePreviewParams(mainKeyboardViewAttr); 3953623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 3966a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3976a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3988335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static void updateGestureHandlingMode() { 3998335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sShouldHandleGesture = sMainDictionaryAvailable 4008335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByInputField 4018335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByUser 4028335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); 4038335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 4048335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 4058335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 406694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 4078335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sMainDictionaryAvailable = mainDictionaryAvailable; 4088335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 4098335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 4108335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 411694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 4128335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; 4138335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 414918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka } 415918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 416694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, final KeyEventHandler handler) { 417b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka final ArrayList<PointerTracker> trackers = sTrackers; 4185c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 4195c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 4205c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 4215c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 4225c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 4235c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4245c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 4255c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 4265c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4275c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 4285c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 42993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.isAnyInSlidingKeyInput(); 4305c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4315c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 4325c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka public static void cancelAllPointerTrackers() { 4335c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka sPointerTrackerQueue.cancelAllPointerTrackers(); 4345c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka } 4355c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka 436694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyboardActionListener(final KeyboardActionListener listener) { 437afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 438afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 439afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 4405c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 4415c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4425c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4435c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 444694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyDetector(final KeyDetector keyDetector) { 445afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 446afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 447afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 4485c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 4495c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 4505c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 4515c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 452918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 4538335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput(); 4548335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 4555c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4565c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 457dde36ef34329164cf8b8a3985c578dab0343b3ebTadashi G. Takaoka public static void setReleasedKeyGraphicsToAllKeys() { 458afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 459afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 460afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 461e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.mCurrentKey); 4625c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4635c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4645c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 465ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang public static void dismissAllMoreKeysPanels() { 466ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final int trackersSize = sTrackers.size(); 467ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang for (int i = 0; i < trackersSize; ++i) { 468ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final PointerTracker tracker = sTrackers.get(i); 469ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (tracker.isShowingMoreKeysPanel()) { 470ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang tracker.mMoreKeysPanel.dismissMoreKeysPanel(); 471ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang tracker.mMoreKeysPanel = null; 472ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 473ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 474ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 475ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 476694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private PointerTracker(final int id, final KeyEventHandler handler) { 477694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (handler == null) { 4785c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 479694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 4805c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 48180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints( 48205124d019352d1aca08de95dbfbd5510b5e9e92cTadashi G. Takaoka id, sGestureStrokeParams, sGesturePreviewParams); 483b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka setKeyEventHandler(handler); 484b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka } 485b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka 486b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka private void setKeyEventHandler(final KeyEventHandler handler) { 4875c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 4885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 4895c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 4905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 4916a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4926a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 4931a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 4948126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key, 495ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka final int repeatCount) { 49613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // While gesture input is going on, this method should be a no-operation. But when gesture 49713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // input has been canceled, <code>sInGesture</code> and <code>mIsDetectingGesture</code> 49813d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // are set to false. To keep this method is a no-operation, 49913d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // <code>mIsTrackingForActionDisabled</code> should also be taken account of. 50013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (sInGesture || mIsDetectingGesture || mIsTrackingForActionDisabled) { 501eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return false; 502eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 5038dfbb740e1015af0cd339a183dd333a5f53c52c4Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); 504e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 5058126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onPress : %s%s%s%s", mPointerId, 50658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka KeyDetector.printableCode(key), 50758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka ignoreModifierKey ? " ignoreModifier" : "", 5088126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka key.isEnabled() ? "" : " disabled", 509ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka repeatCount > 0 ? " repeatCount=" + repeatCount : "")); 510e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 51193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (ignoreModifierKey) { 512996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 51393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 514e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 5157dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka mListener.onPressKey(key.getCode(), repeatCount, getActivePointerTrackerCount() == 1); 516690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 517690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 518d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 519690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 520690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 521690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 522dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 523dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 524690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 525690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 526694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, 5273623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final int y, final long eventTime) { 5288dfbb740e1015af0cd339a183dd333a5f53c52c4Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); 5296bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 53029d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int code = altersCode ? key.getAltCode() : primaryCode; 5312013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (DEBUG_LISTENER) { 532240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final String output = code == Constants.CODE_OUTPUT_TEXT 533240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka ? key.getOutputText() : Constants.printableCode(code); 53458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y, 53558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka output, ignoreModifierKey ? " ignoreModifier" : "", 53658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled")); 5372013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5389c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 5399bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, 5409bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge altersCode, code); 5419bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 542e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 543996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 544e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 5456bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 5466bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.isEnabled() || altersCode) { 5473623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onCodeInput(code, eventTime); 548240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (code == Constants.CODE_OUTPUT_TEXT) { 54929d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka mListener.onTextInput(key.getOutputText()); 550240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (code != Constants.CODE_UNSPECIFIED) { 551ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mListener.onCodeInput(code, x, y); 5522013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 55393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 554dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 555dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 556f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may be in shifted state and the 557690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 558694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnRelease(final Key key, final int primaryCode, 559694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final boolean withSliding) { 56013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // See the comment at {@link #callListenerOnPressAndCheckKeyboardLayoutChange(Key}}. 56113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (sInGesture || mIsDetectingGesture || mIsTrackingForActionDisabled) { 562eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 563eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 5648dfbb740e1015af0cd339a183dd333a5f53c52c4Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); 565e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 56658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, 567240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka Constants.printableCode(primaryCode), 56858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "", 56958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "": " disabled")); 570e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 5719c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 5729bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, 5739bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ignoreModifierKey); 5749bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 575e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 576996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 577e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 57893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (key.isEnabled()) { 5792a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onReleaseKey(primaryCode, withSliding); 58093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 581dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 582dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 58341016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka private void callListenerOnFinishSlidingInput() { 58441016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka if (DEBUG_LISTENER) { 58541016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onFinishSlidingInput", mPointerId)); 58641016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 58741016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka mListener.onFinishSlidingInput(); 58841016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 58941016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka 5908aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 591694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_LISTENER) { 59258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelInput", mPointerId)); 593694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 5949c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 5959bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCancelInput(); 5969bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 5978aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 598dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 599dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 600694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setKeyDetectorInner(final KeyDetector keyDetector) { 60158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 60258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (keyDetector == mKeyDetector && keyboard == mKeyboard) { 60358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return; 60458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 605a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 6065a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 607d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyWidth = mKeyboard.mMostCommonKeyWidth; 608d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyHeight = mKeyboard.mMostCommonKeyHeight; 609b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); 6108a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); 6118a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (newKey != mCurrentKey) { 6128a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (mDrawingProxy != null) { 6138a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 6148a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 61544972bcdb6f6dd0e4f02a26f31c7effaf0525403Tadashi G. Takaoka // Keep {@link #mCurrentKey} that comes from previous keyboard. 6168a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 617b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); 618d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mBogusMoveEventDetector.setKeyboardGeometry(keyWidth, keyHeight); 6195a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 6205a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 6210cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 622cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 623cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 624cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 625cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 626e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKey() { 627e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey; 628dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 629dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 6300cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 6312aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 632e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey != null && mCurrentKey.isModifier(); 6332aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 6342aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 635694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public Key getKeyOn(final int x, final int y) { 636723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 6372aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 6382aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 639694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setReleasedKeyGraphics(final Key key) { 640d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 6416bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 642faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 643faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 644faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 6456bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, update the key release graphics just in case. 646faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(key); 647faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 648faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 649faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 650faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 651faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(shiftKey); 6522013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6532013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 654faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 6552013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 656faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.altCodeWhileTyping()) { 65729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 658faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 659faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 660faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(altKey); 661faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 662faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 66329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 664faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(k); 6652013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6662013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6676a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6686a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6696a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 67029d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 67129d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!sShouldHandleGesture) return false; 6723623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime); 67329d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka } 67429d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka 67529d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void setPressedKeyGraphics(final Key key, final long eventTime) { 6766bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 6776bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka return; 6786bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 6796bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka 6806bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 6816bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 6826bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; 6836bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (!needsToUpdateGraphics) { 684faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 685faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 686faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 68729d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!key.noKeyPreview() && !sInGesture && !needsToSuppressKeyPreviewPopup(eventTime)) { 688faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.showKeyPreview(this); 689faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 690faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(key); 691faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 692faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 693faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 694faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 695faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(shiftKey); 6962013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6972013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 698faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 6992013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 70073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) { 70129d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 702faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 703faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 704faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(altKey); 705faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 706faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 70729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 708faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(k); 7092013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 7102013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 711d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 712c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 713c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 714694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updateReleaseKeyGraphics(final Key key) { 715faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onReleased(); 716faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 717faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 718faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 719694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updatePressKeyGraphics(final Key key) { 720faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onPressed(); 721faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 722faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 723faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 724c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { 725c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka return mGestureStrokeWithPreviewPoints; 7262f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 7272f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang 728547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void getLastCoordinates(final int[] outCoords) { 729547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.set(outCoords, mLastX, mLastY); 7308a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7318a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 7328a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 7338a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 7348a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7358a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 736547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka public void getDownCoordinates(final int[] outCoords) { 737547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.copy(outCoords, mDownCoordinates); 738547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka } 739547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka 740694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onDownKey(final int x, final int y, final long eventTime) { 7418a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 742547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.set(mDownCoordinates, x, y); 743b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onDownKey(); 7448a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 7458a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7468a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 747b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static int getDistance(final int x1, final int y1, final int x2, final int y2) { 748b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return (int)Math.hypot(x1 - x2, y1 - y2); 749b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 750b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 751694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKeyInternal(final int x, final int y) { 752b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onMoveKey(getDistance(x, y, mLastX, mLastY)); 7538a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 7548a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 755723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 7568a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7578a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 758694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKey(final int x, final int y) { 7598a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 7608a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7618a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 762694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveToNewKey(final Key newKey, final int x, final int y) { 763e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mCurrentKey = newKey; 7648a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 7658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 766e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return newKey; 7678a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 7688a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 7696c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static int getActivePointerTrackerCount() { 77093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.size(); 7716c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7726c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 773212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka private boolean isOldestTrackerInQueue() { 774ab334eb64669e909f0a401fddffa891962002602Tadashi G. Takaoka return sPointerTrackerQueue.getOldestElement() == this; 77513ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka } 77613ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka 7771645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka private void mayStartBatchInput(final Key key) { 778c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { 7799c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka return; 7809c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka } 7817dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka if (key == null || !Character.isLetter(key.getCode())) { 7821645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka return; 7831645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka } 7849c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka if (DEBUG_LISTENER) { 78558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); 7869580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7879c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka sInGesture = true; 78858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka synchronized (sAggregratedPointers) { 78958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sAggregratedPointers.reset(); 79058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionPointSize = 0; 79158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionTime = 0; 79258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mListener.onStartBatchInput(); 793ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang dismissAllMoreKeysPanels(); 79458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 795ad181915f78235bc09e88c85ed9df669801b8442Tadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 796212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka // A gesture floating preview text will be shown at the oldest pointer/finger on the screen. 797212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mDrawingProxy.showGestureTrail( 798212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka this, isOldestTrackerInQueue() /* showsFloatingPreviewText */); 7996c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8006c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 80172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void updateBatchInputByTimer(final long eventTime) { 80272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 80372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.duplicateLastPointWith(gestureTime); 80472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka updateBatchInput(eventTime); 80572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 80672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 807157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka private void mayUpdateBatchInput(final long eventTime, final Key key) { 808157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (key != null) { 80972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka updateBatchInput(eventTime); 81072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 81113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 8126f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka return; 8136f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka } 814212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka // A gesture floating preview text will be shown at the oldest pointer/finger on the screen. 815212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mDrawingProxy.showGestureTrail( 816212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka this, isOldestTrackerInQueue() /* showsFloatingPreviewText */); 81772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 81872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 81972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private void updateBatchInput(final long eventTime) { 82072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka synchronized (sAggregratedPointers) { 82172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final GestureStroke stroke = mGestureStrokeWithPreviewPoints; 82272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka stroke.appendIncrementalBatchPoints(sAggregratedPointers); 82372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int size = sAggregratedPointers.getPointerSize(); 82472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (size > sLastRecognitionPointSize 82572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) { 82672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (DEBUG_LISTENER) { 82772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, 82872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka size)); 8296c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 83072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mTimerProxy.startUpdateBatchInputTimer(this); 83172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mListener.onUpdateBatchInput(sAggregratedPointers); 832b1e6eeea57794518997f449a4e4b947be4f74b0eJean Chalard // The listener may change the size of the pointers (when auto-committing 833b1e6eeea57794518997f449a4e4b947be4f74b0eJean Chalard // for example), so we need to get the size from the pointers again. 834b1e6eeea57794518997f449a4e4b947be4f74b0eJean Chalard sLastRecognitionPointSize = sAggregratedPointers.getPointerSize(); 835b1e6eeea57794518997f449a4e4b947be4f74b0eJean Chalard sLastRecognitionTime = eventTime; 8366c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8379580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8389580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8399580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 84029d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void mayEndBatchInput(final long eventTime) { 8416c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka synchronized (sAggregratedPointers) { 842c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); 8436c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 8446c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sInGesture = false; 8453623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onEndBatchInput(eventTime); 846b5fc0e02d04550d39bfa98c2dde805f1c1d3f9a3Tadashi G. Takaoka mTimerProxy.cancelAllUpdateBatchInputTimers(); 84713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (!mIsTrackingForActionDisabled) { 848b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (DEBUG_LISTENER) { 849b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", 850b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mPointerId, sAggregratedPointers.getPointerSize())); 851b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 852b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mListener.onEndBatchInput(sAggregratedPointers); 853b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 8546c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8559580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 85613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 8576f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka return; 8586f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka } 859212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka // A gesture floating preview text will be shown at the oldest pointer/finger on the screen. 860212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mDrawingProxy.showGestureTrail( 861212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka this, isOldestTrackerInQueue() /* showsFloatingPreviewText */); 8629580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8639580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 8648e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka private void cancelBatchInput() { 8655c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka cancelAllPointerTrackers(); 8668353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka mIsDetectingGesture = false; 8677c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka if (!sInGesture) { 8687c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka return; 8697c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka } 8708e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sInGesture = false; 8718e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka if (DEBUG_LISTENER) { 8728e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelBatchInput", mPointerId)); 8738e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } 8748e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka mListener.onCancelBatchInput(); 8758e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } 8768e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka 877e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka public void processMotionEvent(final MotionEvent me, final KeyEventHandler handler) { 878e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int action = me.getActionMasked(); 879e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final long eventTime = me.getEventTime(); 880e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka if (action == MotionEvent.ACTION_MOVE) { 881e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int pointerCount = me.getPointerCount(); 882e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka for (int index = 0; index < pointerCount; index++) { 883e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int id = me.getPointerId(index); 884e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final PointerTracker tracker = getPointerTracker(id, handler); 885e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int x = (int)me.getX(index); 886e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int y = (int)me.getY(index); 887e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka tracker.onMoveEvent(x, y, eventTime, me); 888e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka } 889e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka return; 890e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka } 891e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int index = me.getActionIndex(); 892e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int x = (int)me.getX(index); 893e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int y = (int)me.getY(index); 8948ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka switch (action) { 8958ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 8968ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 8978ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onDownEvent(x, y, eventTime, handler); 8988ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 8998ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_UP: 9008ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 9018ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onUpEvent(x, y, eventTime); 9028ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 9038ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 9048ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onCancelEvent(x, y, eventTime); 9058ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 9068ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 9078ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 9088ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 909e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka private void onDownEvent(final int x, final int y, final long eventTime, 910694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 911694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 912dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 913694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 914b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka setKeyEventHandler(handler); 915baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 9168a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 917160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka if (deltaT < sParams.mTouchNoiseThresholdTime) { 918b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final int distance = getDistance(x, y, mLastX, mLastY); 919b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (distance < sParams.mTouchNoiseThresholdDistance) { 920faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 921b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onDownEvent:" 922b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " ignore potential noise: time=%d distance=%d", 923b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, deltaT, distance)); 9249c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 925b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance); 9269bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 92713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 928baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 929baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 930baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 931baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 932eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final Key key = getKeyOn(x, y); 933b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onActualDownEvent(x, y); 93493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (key != null && key.isModifier()) { 93593b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 93693b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 93793b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 9381d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 93993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.add(this); 9401d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 9416c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!sShouldHandleGesture) { 9426c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 9436c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 9440938fb6913c10d32f0a870210fc208c7bbfe282cSatoshi Kataoka // A gesture should start only from a non-modifier key. Note that the gesture detection is 9450938fb6913c10d32f0a870210fc208c7bbfe282cSatoshi Kataoka // disabled when the key is repeating. 946b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() 9470938fb6913c10d32f0a870210fc208c7bbfe282cSatoshi Kataoka && key != null && !key.isModifier(); 948b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (mIsDetectingGesture) { 949b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 9506c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sGestureFirstDownTime = eventTime; 9519580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 95258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime, 9533623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.getLastLetterTypingTime()); 954eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 9551d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9561d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 95735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private boolean isShowingMoreKeysPanel() { 95835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return (mMoreKeysPanel != null); 95935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 96035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 961694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void onDownEventInternal(final int x, final int y, final long eventTime) { 962e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onDownKey(x, y, eventTime); 96367a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 96432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. 965160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mIsAllowedSlidingKeyInput = sParams.mSlidingKeyInputEnabled 966c9f203805ca23276fcdcdc79b9298bc1d413ad98Tadashi G. Takaoka || (key != null && key.isModifier()) 96732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka || mKeyDetector.alwaysAllowsSlidingInput(); 9681a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 96913d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka mIsTrackingForActionDisabled = false; 970f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 971e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 9721a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 973e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the new 9741a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 975ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) { 976e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onDownKey(x, y, eventTime); 977e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 978996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 979e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 980e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 98129d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 9826a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9836a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9846a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 985694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startSlidingKeyInput(final Key key) { 986e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (!mIsInSlidingKeyInput) { 987f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = key.isModifier(); 988e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 989996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 990996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 991996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 992f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka private void resetSlidingKeyInput() { 993f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInput = false; 994f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = false; 99508d8a676c28f30a722629cb4713177064f6422e2Tadashi G. Takaoka mDrawingProxy.dismissSlidingKeyInputPreview(); 996f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka } 997f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka 9986c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onGestureMoveEvent(final int x, final int y, final long eventTime, 99902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final boolean isMajorEvent, final Key key) { 10006c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 10016c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (mIsDetectingGesture) { 1002b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka final int beforeLength = mGestureStrokeWithPreviewPoints.getLength(); 1003b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka final boolean onValidArea = mGestureStrokeWithPreviewPoints.addPointOnKeyboard( 1004b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka x, y, gestureTime, isMajorEvent); 1005b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka if (mGestureStrokeWithPreviewPoints.getLength() > beforeLength) { 1006b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka mTimerProxy.startUpdateBatchInputTimer(this); 1007b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka } 10088353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka // If the move event goes out from valid batch input area, cancel batch input. 1009b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka if (!onValidArea) { 10108e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka cancelBatchInput(); 1011b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka return; 1012b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1013ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang // If the MoreKeysPanel is showing then do not attempt to enter gesture mode. However, 1014ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang // the gestured touch points are still being recorded in case the panel is dismissed. 1015ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 1016ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang return; 1017ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 10181645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka mayStartBatchInput(key); 1019157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (sInGesture) { 1020157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mayUpdateBatchInput(eventTime, key); 10219580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 10229580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 10239580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 10249580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 1025e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka private void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) { 1026694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_MOVE_EVENT) { 1027dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 1028694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 102913d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 1030e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 1031694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1032baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 10336c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture && me != null) { 1034eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Add historical points to gesture path. 1035eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int pointerIndex = me.findPointerIndex(mPointerId); 1036eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalSize = me.getHistorySize(); 1037eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int h = 0; h < historicalSize; h++) { 1038eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalX = (int)me.getHistoricalX(pointerIndex, h); 1039eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalY = (int)me.getHistoricalY(pointerIndex, h); 1040eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final long historicalTime = me.getHistoricalEventTime(h); 10416c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onGestureMoveEvent(historicalX, historicalY, historicalTime, 104202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka false /* isMajorEvent */, null); 1043eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1044eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1045ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 1046ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 1047ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka final int translatedX = mMoreKeysPanel.translateX(x); 1048ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka final int translatedY = mMoreKeysPanel.translateY(y); 1049ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime); 1050ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka onMoveKey(x, y); 1051212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka if (mIsInSlidingKeyInputFromModifier) { 1052212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mDrawingProxy.showSlidingKeyInputPreview(this); 1053212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 1054ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang return; 1055ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 10566c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onMoveEventInternal(x, y, eventTime); 10576c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 10586c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 10593c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processSlidingKeyInput(final Key newKey, final int x, final int y, 10603c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime) { 10613c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 10623c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update key according 10633c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // to the new keyboard layout. 10643c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Key key = newKey; 1065ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) { 10663c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka key = onMoveKey(x, y); 10673c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10683c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onMoveToNewKey(key, x, y); 106913d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 107013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka return; 107113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka } 10723c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka startLongPressTimer(key); 10733c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 10743c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10753c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 10763c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processPhantomSuddenMoveHack(final Key key, final int x, final int y, 10773c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 10783c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 10793c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 10803c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " phantom sudden move event (distance=%d) is translated to " 10813c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, 10823c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka getDistance(x, y, lastX, lastY), 10837dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.getCode()), 10847dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka x, y, Constants.printableCode(key.getCode()))); 10853c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10863c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // TODO: This should be moved to outside of this nested if-clause? 10879c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 10883c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); 10893c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 109035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 10913c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 10923c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 10933c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 10943c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processProximateBogusDownMoveUpEventHack(final Key key, final int x, final int y, 10953c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 10963c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 10973c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 10983c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 10993c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float radiusRatio = 11003c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mBogusMoveEventDetector.getDistanceFromDownEvent(x, y) 11013c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka / keyDiagonal; 11023c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 11033c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " bogus down-move-up event (raidus=%.2f key diagonal) is " 11043c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " translated to up[%d,%d,%s]/down[%d,%d,%s] events", 11053c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mPointerId, radiusRatio, 11067dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.getCode()), 11077dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka x, y, Constants.printableCode(key.getCode()))); 11083c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 110935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 11103c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 11113c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 11123c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 1113831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka private void processSildeOutFromOldKey(final Key oldKey) { 1114831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 11157dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.getCode(), true /* withSliding */); 1116831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka startSlidingKeyInput(oldKey); 1117831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1118831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } 1119831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka 11203c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void slideFromOldKeyToNewKey(final Key key, final int x, final int y, 11218b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 11228b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 11238b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 11248b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onPress() to notify that the new key is being pressed. 1125831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSildeOutFromOldKey(oldKey); 11268b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka startRepeatKey(key); 11278b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 11283c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka processSlidingKeyInput(key, x, y, eventTime); 11292a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 11302a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be reported as a sudden move by 11312a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // touch panel firmware. This hack detects such cases and translates the move event to 11322a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // successive up and down events. 11332a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // TODO: Should find a way to balance gesture detection and this hack. 11342a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsPhantomSuddenMoveEventHack 11352a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) { 11362a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processPhantomSuddenMoveHack(key, x, y, eventTime, oldKey, lastX, lastY); 11372a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 11382a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive proximate touches may be reported as a bogus 11392a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // down-move-up event by touch panel firmware. This hack detects such cases and breaks 11402a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // these events into separate up and down events. 11412a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsProximateBogusDownMoveUpEventHack && sTimeRecorder.isInFastTyping(eventTime) 11422a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { 11432a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY); 11442a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 11452a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: If there are currently multiple touches, register the key even if the finger 11462a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // slides off the key. This defends against noise from some touch panels when there are 11472a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // close multiple touches. 11482a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // Caveat: When in chording input mode with a modifier key, we don't use this hack. 114993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka else if (getActivePointerTrackerCount() > 1 11502a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { 11512a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (DEBUG_MODE) { 11522a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 11532a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka + " detected sliding finger while multi touching", mPointerId)); 11543c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 11552a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka onUpEvent(x, y, eventTime); 115613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 11572a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka setReleasedKeyGraphics(oldKey); 11582a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } else { 11592a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (!mIsDetectingGesture) { 116013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 11618b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11622a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka setReleasedKeyGraphics(oldKey); 11638b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11648b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11658b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 11668b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka private void slideOutFromOldKey(final Key oldKey, final int x, final int y) { 11678b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 11688b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // notify that the previous key has been released. 1169831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSildeOutFromOldKey(oldKey); 11708b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 11718b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onMoveToNewKey(null, x, y); 11728b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } else { 11738b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (!mIsDetectingGesture) { 117413d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 11758b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11768b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11778b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 11788b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 11796c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onMoveEventInternal(final int x, final int y, final long eventTime) { 11808a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 11818a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 1182e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key oldKey = mCurrentKey; 11838b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final Key newKey = onMoveKey(x, y); 1184eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 11856c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture) { 11866c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // Register move event on gesture tracker. 11878b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey); 11886c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 11896c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 11906c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 11916c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 11926c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 1193eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1194eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 11958b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (newKey != null) { 11963c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 11978b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka slideFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY); 11983c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } else if (oldKey == null) { 1199831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 1200831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 1201831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka processSlidingKeyInput(newKey, x, y, eventTime); 1202c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 1203831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } else { // newKey == null 12048b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 12058b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka slideOutFromOldKey(oldKey, x, y); 120607221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 12076a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1208212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka if (mIsInSlidingKeyInputFromModifier) { 1209212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mDrawingProxy.showSlidingKeyInputPreview(this); 1210212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 12116a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12126a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1213e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka private void onUpEvent(final int x, final int y, final long eventTime) { 1214694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1215dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 1216694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 12171d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1218915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka mTimerProxy.cancelUpdateBatchInputTimer(this); 121993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (!sInGesture) { 122093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (mCurrentKey != null && mCurrentKey.isModifier()) { 122193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing an up event of modifier key, all pointers already being 122293b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 122393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime); 122493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka } else { 122593b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime); 12261d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 12271d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 122835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 122993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 12301d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 12311d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1232d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 1233d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 1234d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 12350cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 1236694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onPhantomUpEvent(final long eventTime) { 1237694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1238547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka printTouchEvent("onPhntEvent:", mLastX, mLastY, eventTime); 1239694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 124035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (isShowingMoreKeysPanel()) { 124135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return; 124235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 124335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(mLastX, mLastY, eventTime); 124413d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 12451d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 12461d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 124735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private void onUpEventInternal(final int x, final int y, final long eventTime) { 12482321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1249e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka final boolean isInSlidingKeyInput = mIsInSlidingKeyInput; 125041016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka final boolean isInSlidingKeyInputFromModifier = mIsInSlidingKeyInputFromModifier; 1251f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 12526c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIsDetectingGesture = false; 12536c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final Key currentKey = mCurrentKey; 12546c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 1255a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka final int currentRepeatingKeyCode = mCurrentRepeatingKeyCode; 1256a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka mCurrentRepeatingKeyCode = Constants.NOT_A_CODE; 12575a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka // Release the last pressed key. 12586c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(currentKey); 125935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 126035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (isShowingMoreKeysPanel()) { 126113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (!mIsTrackingForActionDisabled) { 126235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedX = mMoreKeysPanel.translateX(x); 126335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedY = mMoreKeysPanel.translateY(y); 126435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.onUpEvent(translatedX, translatedY, mPointerId, eventTime); 126535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 126635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.dismissMoreKeysPanel(); 126735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel = null; 126835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return; 12699ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 1270eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 12716c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 12726c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null) { 12737dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka callListenerOnRelease(currentKey, currentKey.getCode(), true /* withSliding */); 1274eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 127529d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka mayEndBatchInput(eventTime); 1276eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 1277eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 127858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 127913d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 1280d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 1281694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1282a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka if (currentKey != null && currentKey.isRepeatable() 1283a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka && (currentKey.getCode() == currentRepeatingKeyCode) && !isInSlidingKeyInput) { 1284e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka return; 12856a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1286e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime); 128741016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka if (isInSlidingKeyInputFromModifier) { 128841016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka callListenerOnFinishSlidingInput(); 128941016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 12906a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12916a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 129233482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka public void onShowMoreKeysPanel(final MoreKeysPanel panel) { 129335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang setReleasedKeyGraphics(mCurrentKey); 129433482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka final int translatedX = panel.translateX(mLastX); 129533482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka final int translatedY = panel.translateY(mLastY); 129633482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka panel.onDownEvent(translatedX, translatedY, mPointerId, SystemClock.uptimeMillis()); 129735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel = panel; 12989ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 12999ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 1300b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka @Override 130113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka public void cancelTrackingForAction() { 13028353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka if (isShowingMoreKeysPanel()) { 13038353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka return; 13048353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka } 130513d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka mIsTrackingForActionDisabled = true; 1306b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1307b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 1308906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 1309547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka resetSlidingKeyInput(); 131013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 1311e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 131293b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 1313d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 1314d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 1315e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka private void onCancelEvent(final int x, final int y, final long eventTime) { 1316694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1317dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 1318694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 13191d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 13207c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka cancelBatchInput(); 13215c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka cancelAllPointerTrackers(); 13228e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 1323baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 13241d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 13251d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1326baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 13272321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1328e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 1329f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 1330ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 1331ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang mMoreKeysPanel.dismissMoreKeysPanel(); 1332ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang mMoreKeysPanel = null; 1333ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 13346a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 13356a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1336b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, 1337b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final Key newKey) { 1338694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyDetector == null) { 1339a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 1340694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1341694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final Key curKey = mCurrentKey; 13426a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 1343e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 1344a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1345a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (curKey == null /* && newKey != null */) { 1346a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1347a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1348a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka // Here curKey points to the different key from newKey. 1349a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( 1350a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mIsInSlidingKeyInputFromModifier); 1351a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); 1352a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { 1353a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1354a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared) 1355a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka / mKeyboard.mMostCommonKeyWidth; 1356a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1357a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka +" %.2f key width from key edge", mPointerId, distanceToEdgeRatio)); 1358b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1359a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1360a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1361a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput 1362a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && sTimeRecorder.isInFastTyping(eventTime) 1363a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) { 1364a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1365a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 1366a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 1367a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float lengthFromDownRatio = 1368a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal; 1369a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1370a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka + " %.2f key diagonal from virtual down point", 1371a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mPointerId, lengthFromDownRatio)); 1372b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1373e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 13746a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1375a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return false; 13766a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 13776a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1378694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startLongPressTimer(final Key key) { 137943ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (sInGesture) return; 138043ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (key == null) return; 138143ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (!key.isLongPressEnabled()) return; 138243ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // Caveat: Please note that isLongPressEnabled() can be true even if the current key 138343ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // doesn't have its more keys. (e.g. spacebar, globe key) 138443ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // We always need to start the long press timer if the key has its more keys regardless of 138543ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // whether or not we are in the sliding input mode. 13867dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka if (mIsInSlidingKeyInput && key.getMoreKeys() == null) return; 1387212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka final int delay; 13887dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka switch (key.getCode()) { 1389212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka case Constants.CODE_SHIFT: 1390212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka delay = sParams.mLongPressShiftLockTimeout; 1391212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka break; 1392212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka default: 1393212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka final int longpressTimeout = Settings.getInstance().getCurrent().mKeyLongpressTimeout; 1394212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka if (mIsInSlidingKeyInputFromModifier) { 1395212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka // We use longer timeout for sliding finger input started from the modifier key. 1396212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka delay = longpressTimeout * MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT; 1397212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } else { 1398212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka delay = longpressTimeout; 1399212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 1400212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka break; 1401212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 1402212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mTimerProxy.startLongPressTimer(this, delay); 140366e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 140466e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 14053623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) { 140683e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 14078aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 1408dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 1409dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 141066e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 14117dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int code = key.getCode(); 14123623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka callListenerOnCodeInput(key, code, x, y, eventTime); 141341016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka callListenerOnRelease(key, code, false /* withSliding */); 14146a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 14156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 14168126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka private void startRepeatKey(final Key key) { 14178126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka if (sInGesture) return; 14188126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka if (key == null) return; 14198126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka if (!key.isRepeatable()) return; 14208126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka // Don't start key repeat when we are in sliding input mode. 14218126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka if (mIsInSlidingKeyInput) return; 1422ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka final int startRepeatCount = 1; 1423ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(this, startRepeatCount, sParams.mKeyRepeatStartTimeout); 14248126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka } 14258126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka 1426ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka public void onKeyRepeat(final int code, final int repeatCount) { 14278126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka final Key key = getKey(); 14287dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka if (key == null || key.getCode() != code) { 1429a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka mCurrentRepeatingKeyCode = Constants.NOT_A_CODE; 14308126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka return; 14318126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka } 1432a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka mCurrentRepeatingKeyCode = code; 14330938fb6913c10d32f0a870210fc208c7bbfe282cSatoshi Kataoka mIsDetectingGesture = false; 1434ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka final int nextRepeatCount = repeatCount + 1; 1435ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(this, nextRepeatCount, sParams.mKeyRepeatInterval); 1436ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka callListenerOnPressAndCheckKeyboardLayoutChange(key, repeatCount); 14378126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis()); 14388126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka } 14398126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka 1440694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void printTouchEvent(final String title, final int x, final int y, 1441694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final long eventTime) { 1442723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka final Key key = mKeyDetector.detectHitKey(x, y); 1443e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka final String code = KeyDetector.printableCode(key); 144458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, 144513d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka (mIsTrackingForActionDisabled ? "-" : " "), title, x, y, eventTime, code)); 1446dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 14476e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 1448