PointerTracker.java revision d631778e1c1ffcdf28129894239e7ee7d6f399fc
16a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka/* 28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 36a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 46a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); you may not 56a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * use this file except in compliance with the License. You may obtain a copy of 66a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * the License at 76a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 86a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 96a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 106a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 116a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 126a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 136a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * License for the specific language governing permissions and limitations under 146a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * the License. 156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka */ 166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 195509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport android.content.res.TypedArray; 20e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaokaimport android.os.SystemClock; 21c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport android.util.Log; 228ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaokaimport android.view.MotionEvent; 23c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 24918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 25f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStroke; 2680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams; 27c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints; 2872934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 295f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils; 30f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 31faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 325509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport com.android.inputmethod.latin.R; 339bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 346b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 356a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 365c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 37dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 38a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class PointerTracker implements PointerTrackerQueue.Element { 39dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 40dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 41dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 42dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 43b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG || DEBUG_EVENT; 4440a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 450657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka /** True if {@link PointerTracker}s should handle gesture events. */ 460657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka private static boolean sShouldHandleGesture = false; 478335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sMainDictionaryAvailable = false; 488335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByInputField = false; 498335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByUser = false; 50918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 51f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public interface KeyEventHandler { 52f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 53f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyDetector object that is used for this PointerTracker. 54f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyDetector object that is used for this PointerTracker 55f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 56f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyDetector getKeyDetector(); 57f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 58f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 59f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyboardActionListener object that is used to register key code and so on. 60f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyboardActionListner for this PointerTracker 61f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 62f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener(); 63f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 64f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 65f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get DrawingProxy object that is used for this PointerTracker. 66f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the DrawingProxy object that is used for this PointerTracker 67f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 68f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy(); 69f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 70f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 71f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get TimerProxy object that handles key repeat and long press timer event for this 72f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * PointerTracker. 73f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the TimerProxy object that handles key repeat and long press timer event. 74f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 75f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public TimerProxy getTimerProxy(); 76f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 77f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 789d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public interface DrawingProxy extends MoreKeysPanel.Controller { 796a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public void invalidateKey(Key key); 80e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public void showKeyPreview(PointerTracker tracker); 81d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void dismissKeyPreview(PointerTracker tracker); 82f0e83046f022b5594f98aef07fbda7f2f837f262Tadashi G. Takaoka public void showGesturePreviewTrail(PointerTracker tracker, boolean isOldestTracker); 836a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 846a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 852321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public interface TimerProxy { 86d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey); 8773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState(); 88a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker); 89a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker); 90a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code); 9198b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer(); 920ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer(); 93beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer(); 940ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout(); 952321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelKeyTimers(); 9629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 9729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static class Adapter implements TimerProxy { 9829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 99d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey) {} 10093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 10173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { return false; } 10293246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 103a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker) {} 10429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 105a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker) {} 106a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 107a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code) {} 10829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 10929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelLongPressTimer() {} 11029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 1110ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer() {} 1120ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 113beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer() {} 114beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 1150ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout() { return false; } 1160ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 11729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelKeyTimers() {} 11829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 1192321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka } 1202321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka 121a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka static final class PointerTrackerParams { 1225509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final boolean mSlidingKeyInputEnabled; 1235509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final int mTouchNoiseThresholdTime; 124b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public final int mTouchNoiseThresholdDistance; 1253623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public final int mSuppressKeyPreviewAfterBatchInputDuration; 1265509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1275509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); 1285509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1295509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private PointerTrackerParams() { 1305509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = false; 1315509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = 0; 132b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = 0; 1333623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 0; 1345509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1355509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 13680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) { 1375509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean( 1385509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_slidingKeyInputEnable, false); 1395509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( 1405509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); 141b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( 1425509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); 1433623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt( 1443623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0); 1455509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1465509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1475509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 148160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka // Parameters for pointer handling. 1495509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private static PointerTrackerParams sParams; 15080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private static GestureStrokeParams sGestureStrokeParams; 151d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka private static boolean sNeedsPhantomSuddenMoveEventHack; 152b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move this threshold to resource. 153b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // TODO: Device specific parameter would be better for device specific hack? 154b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth 155b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // This hack might be device specific. 156b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final boolean sNeedsProximateBogusDownMoveUpEventHack = true; 1575c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1585f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); 1595c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static PointerTrackerQueue sPointerTrackerQueue; 1605c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1615c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 1626a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1630efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 1640efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 165a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 166dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private KeyboardActionListener mListener = EMPTY_LISTENER; 167baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1685a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 169b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mPhantonSuddenMoveThreshold; 170b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); 1716a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1726c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private boolean mIsDetectingGesture = false; // per PointerTracker. 1736c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static boolean sInGesture = false; 1746c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static long sGestureFirstDownTime; 1753623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private static TimeRecorder sTimeRecorder; 1766c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static final InputPointers sAggregratedPointers = new InputPointers( 1776c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka GestureStroke.DEFAULT_CAPACITY); 17858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers 17958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers 1809580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 181b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static final class BogusMoveEventDetector { 182b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move these thresholds to resource. 183d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // These thresholds' unit is a diagonal length of a key. 184d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f; 185d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f; 186b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 187b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mAccumulatedDistanceThreshold; 188b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mRadiusThreshold; 189b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 190b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Accumulated distance from actual and artificial down keys. 191b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int mAccumulatedDistanceFromDownKey; 192b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownX; 193b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private int mActualDownY; 194b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 195d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public void setKeyboardGeometry(final int keyWidth, final int keyHeight) { 196d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight); 197b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceThreshold = (int)( 198d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); 199d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD); 200b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 201b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 202b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onActualDownEvent(final int x, final int y) { 203b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownX = x; 204b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mActualDownY = y; 205b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 206b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 207b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onDownKey() { 208b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey = 0; 209b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 210b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 211b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public void onMoveKey(final int distance) { 212b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mAccumulatedDistanceFromDownKey += distance; 213b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 214b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 215d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka public boolean hasTraveledLongDistance(final int x, final int y) { 216d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dx = Math.abs(x - mActualDownX); 217d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int dy = Math.abs(y - mActualDownY); 218d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // A bogus move event should be a horizontal movement. A vertical movement might be 219d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka // a sloppy typing and should be ignored. 220d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; 221b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 222b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 223b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka /* package */ int getDistanceFromDownEvent(final int x, final int y) { 224b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistance(x, y, mActualDownX, mActualDownY); 225b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 226b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 227b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isCloseToActualDownEvent(final int x, final int y) { 228b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return getDistanceFromDownEvent(x, y) < mRadiusThreshold; 229b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 230b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 231b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2323623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka static final class TimeRecorder { 2333623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mSuppressKeyPreviewAfterBatchInputDuration; 2343623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private final int mStaticTimeThresholdAfterFastTyping; // msec 2353623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastTypingTime; 2363623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastLetterTypingTime; 2373623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private long mLastBatchInputTime; 2383623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2393623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public TimeRecorder(final PointerTrackerParams pointerTrackerParams, 2403623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final GestureStrokeParams gestureStrokeParams) { 2413623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = 2423623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka pointerTrackerParams.mSuppressKeyPreviewAfterBatchInputDuration; 2433623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = 2443623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka gestureStrokeParams.mStaticTimeThresholdAfterFastTyping; 2453623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2463623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 247b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public boolean isInFastTyping(final long eventTime) { 248b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; 249b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; 250b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 251b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 2527a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka private boolean wasLastInputTyping() { 2537a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return mLastTypingTime >= mLastBatchInputTime; 2543623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2553623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2563623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onCodeInput(final int code, final long eventTime) { 2577a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // Record the letter typing time when 2587a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 1. Letter keys are typed successively without any batch input in between. 2597a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 2. A letter key is typed within the threshold time since the last any key typing. 2607a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // 3. A non-letter key is typed within the threshold time since the last letter key 2617a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka // typing. 2627a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (Character.isLetter(code)) { 2637a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (wasLastInputTyping() 2647a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) { 2657a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2663623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2673623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } else { 2683623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) { 2693623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // This non-letter typing should be treated as a part of fast typing. 2707a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastLetterTypingTime = eventTime; 2713623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2723623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2737a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastTypingTime = eventTime; 2743623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2753623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2763623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public void onEndBatchInput(final long eventTime) { 2777a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka mLastBatchInputTime = eventTime; 2783623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2793623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2803623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public long getLastLetterTypingTime() { 2813623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return mLastLetterTypingTime; 2823623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2833623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2843623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 2857a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return !wasLastInputTyping() 2863623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration; 2873623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2883623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 2893623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka 2908a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 2918a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 2928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 2938a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 294e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The current key where this pointer is. 295e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mCurrentKey = null; 296e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The position where the current key was recognized for the first time. 2978a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 2988a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 2998a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3008a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 3018a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 3028a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 3036a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3041a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 3051a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 3061a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 3079ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka // true if event is already translated to a key action. 308c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka private boolean mKeyAlreadyProcessed; 309c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 3109d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka // true if this pointer has been long-pressed and is showing a more keys panel. 3119d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private boolean mIsShowingMoreKeysPanel; 3129ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 313f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input. 3145c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 315f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if this pointer is in a sliding key input from a modifier key, 316f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // so that further modifier keys should be ignored. 317f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka boolean mIsInSlidingKeyInputFromModifier; 318cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 319f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // true if a sliding key input is allowed. 32067a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 32167a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 322dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Empty {@link KeyboardActionListener} 323e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka private static final KeyboardActionListener EMPTY_LISTENER = 324e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka new KeyboardActionListener.Adapter(); 3256e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka 326c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; 327f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 328d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka public static void init(boolean hasDistinctMultitouch, 32962b8dddb6ddb057555a1665759f9cf197e480c9fTadashi G. Takaoka boolean needsPhantomSuddenMoveEventHack) { 3305c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (hasDistinctMultitouch) { 3315c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = new PointerTrackerQueue(); 3325c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } else { 3335c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = null; 3345c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 335d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack; 3365509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = PointerTrackerParams.DEFAULT; 33780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = GestureStrokeParams.DEFAULT; 3383623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 339160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 34093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3415509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static void setParameters(final TypedArray mainKeyboardViewAttr) { 3425509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = new PointerTrackerParams(mainKeyboardViewAttr); 34380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr); 3443623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); 3456a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3466a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3478335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static void updateGestureHandlingMode() { 3488335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sShouldHandleGesture = sMainDictionaryAvailable 3498335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByInputField 3508335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByUser 3518335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); 3528335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 3538335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 3548335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 355694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 3568335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sMainDictionaryAvailable = mainDictionaryAvailable; 3578335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 3588335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 3598335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 360694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 3618335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; 3628335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 363918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka } 364918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 365694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, final KeyEventHandler handler) { 366b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka final ArrayList<PointerTracker> trackers = sTrackers; 3675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3685c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 3695c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 3705c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 3715c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 3725c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3735c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3745c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 3755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3765c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 3775c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 3785c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return sPointerTrackerQueue != null ? sPointerTrackerQueue.isAnyInSlidingKeyInput() : false; 3795c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3805c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 381694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyboardActionListener(final KeyboardActionListener listener) { 382afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 383afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 384afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 3855c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 3865c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3875c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 389694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyDetector(final KeyDetector keyDetector) { 390afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 391afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 392afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 3935c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 3945c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 3955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 3965c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 397918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 3988335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput(); 3998335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 4005c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4015c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 402dde36ef34329164cf8b8a3985c578dab0343b3ebTadashi G. Takaoka public static void setReleasedKeyGraphicsToAllKeys() { 403afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 404afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 405afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 406e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.mCurrentKey); 4075c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4085c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 4095c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 410694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private PointerTracker(final int id, final KeyEventHandler handler) { 411694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (handler == null) { 4125c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 413694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 4145c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 41580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints( 41680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka id, sGestureStrokeParams); 4175c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 4185c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 4195c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 4205c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 4216a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4226a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 4231a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 424694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key) { 4256c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 426eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return false; 427eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 428f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 429e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 43058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId, 43158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka KeyDetector.printableCode(key), 43258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka ignoreModifierKey ? " ignoreModifier" : "", 43358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "" : " disabled")); 434e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 43593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (ignoreModifierKey) { 436996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 43793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 438e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 4392a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onPressKey(key.mCode); 440690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 441690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 442d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 443690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 444690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 445690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 446dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 447dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 448690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 449690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 450694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, 4513623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka final int y, final long eventTime) { 452f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 4536bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 45429d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int code = altersCode ? key.getAltCode() : primaryCode; 4552013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (DEBUG_LISTENER) { 45658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final String output = code == Keyboard.CODE_OUTPUT_TEXT 45758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka ? key.getOutputText() : Keyboard.printableCode(code); 45858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y, 45958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka output, ignoreModifierKey ? " ignoreModifier" : "", 46058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled")); 4612013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4629bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4639bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, 4649bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge altersCode, code); 4659bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 466e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 467996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 468e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 4696bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 4706bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.isEnabled() || altersCode) { 4713623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onCodeInput(code, eventTime); 4728cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka if (code == Keyboard.CODE_OUTPUT_TEXT) { 47329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka mListener.onTextInput(key.getOutputText()); 4748cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka } else if (code != Keyboard.CODE_UNSPECIFIED) { 475ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mListener.onCodeInput(code, x, y); 4762013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 47793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 478dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 479dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 480f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may be in shifted state and the 481690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 482694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnRelease(final Key key, final int primaryCode, 483694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final boolean withSliding) { 4846c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 485eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 486eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 487f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final boolean ignoreModifierKey = mIsInSlidingKeyInputFromModifier && key.isModifier(); 488e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 48958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, 49058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Keyboard.printableCode(primaryCode), 49158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "", 49258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "": " disabled")); 493e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 4949bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4959bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, 4969bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ignoreModifierKey); 4979bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 498e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 499996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 500e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 50193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (key.isEnabled()) { 5022a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onReleaseKey(primaryCode, withSliding); 50393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 504dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 505dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 5068aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 507694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_LISTENER) { 50858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelInput", mPointerId)); 509694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 5109bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 5119bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCancelInput(); 5129bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 5138aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 514dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 515dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 516694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setKeyDetectorInner(final KeyDetector keyDetector) { 51758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 51858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (keyDetector == mKeyDetector && keyboard == mKeyboard) { 51958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return; 52058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 521a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 5225a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 523d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyWidth = mKeyboard.mMostCommonKeyWidth; 524d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyHeight = mKeyboard.mMostCommonKeyHeight; 525d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth); 5268a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); 5278a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (newKey != mCurrentKey) { 5288a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (mDrawingProxy != null) { 5298a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 5308a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 53144972bcdb6f6dd0e4f02a26f31c7effaf0525403Tadashi G. Takaoka // Keep {@link #mCurrentKey} that comes from previous keyboard. 5328a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 533b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); 534d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mBogusMoveEventDetector.setKeyboardGeometry(keyWidth, keyHeight); 5355a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 5365a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 5370cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 538cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 539cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 540cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 541cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 542e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKey() { 543e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey; 544dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 545dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 5460cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 5472aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 548e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey != null && mCurrentKey.isModifier(); 5492aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 5502aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 551694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public Key getKeyOn(final int x, final int y) { 552723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 5532aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 5542aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 555694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setReleasedKeyGraphics(final Key key) { 556d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 5576bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 558faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 559faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 560faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 5616bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, update the key release graphics just in case. 562faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(key); 563faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 564faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 565faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 566faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 567faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(shiftKey); 5682013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5692013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 570faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 5712013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 572faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.altCodeWhileTyping()) { 57329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 574faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 575faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 576faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(altKey); 577faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 578faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 57929d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 580faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(k); 5812013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5822013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5836a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5846a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5856a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 58629d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 58729d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!sShouldHandleGesture) return false; 5883623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime); 58929d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka } 59029d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka 59129d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void setPressedKeyGraphics(final Key key, final long eventTime) { 5926bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 5936bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka return; 5946bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 5956bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka 5966bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 5976bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 5986bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; 5996bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (!needsToUpdateGraphics) { 600faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 601faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 602faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 60329d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka if (!key.noKeyPreview() && !sInGesture && !needsToSuppressKeyPreviewPopup(eventTime)) { 604faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.showKeyPreview(this); 605faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 606faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(key); 607faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 608faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 609faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 610faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 611faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(shiftKey); 6122013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6132013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 614faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 6152013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 61673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) { 61729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 618faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 619faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 620faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(altKey); 621faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 622faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 62329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 624faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(k); 6252013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 6262013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 627d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 628c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 629c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 630694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updateReleaseKeyGraphics(final Key key) { 631faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onReleased(); 632faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 633faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 634faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 635694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updatePressKeyGraphics(final Key key) { 636faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onPressed(); 637faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 638faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 639faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 640c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { 641c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka return mGestureStrokeWithPreviewPoints; 6422f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 6432f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang 6448a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastX() { 6458a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastX; 6468a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6478a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 6488a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastY() { 6498a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastY; 6508a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6518a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 6528a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 6538a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 6548a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6558a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 656694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onDownKey(final int x, final int y, final long eventTime) { 6578a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 658b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onDownKey(); 6598a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 6608a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6618a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 662b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka static int getDistance(final int x1, final int y1, final int x2, final int y2) { 663b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return (int)Math.hypot(x1 - x2, y1 - y2); 664b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 665b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 666694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKeyInternal(final int x, final int y) { 667b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onMoveKey(getDistance(x, y, mLastX, mLastY)); 6688a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 6698a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 670723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 6718a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6728a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 673694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKey(final int x, final int y) { 6748a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 6758a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6768a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 677694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveToNewKey(final Key newKey, final int x, final int y) { 678e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mCurrentKey = newKey; 6798a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 6808a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 681e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return newKey; 6828a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 6838a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 6846c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static int getActivePointerTrackerCount() { 6856c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return (sPointerTrackerQueue == null) ? 1 : sPointerTrackerQueue.size(); 6866c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 6876c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 6881645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka private void mayStartBatchInput(final Key key) { 689c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { 6909c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka return; 6919c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka } 6921645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka if (key == null || !Character.isLetter(key.mCode)) { 6931645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka return; 6941645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka } 6959c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka if (DEBUG_LISTENER) { 69658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); 6979580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 6989c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka sInGesture = true; 69958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka synchronized (sAggregratedPointers) { 70058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sAggregratedPointers.reset(); 70158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionPointSize = 0; 70258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka sLastRecognitionTime = 0; 70358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mListener.onStartBatchInput(); 70458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 705350fab6dc4d4d4aec272056004cbb5c039f5bf37Tadashi G. Takaoka final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; 706350fab6dc4d4d4aec272056004cbb5c039f5bf37Tadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); 7076c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7086c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 709157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka private void mayUpdateBatchInput(final long eventTime, final Key key) { 710157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (key != null) { 711157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka synchronized (sAggregratedPointers) { 71280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka final GestureStroke stroke = mGestureStrokeWithPreviewPoints; 71380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka stroke.appendIncrementalBatchPoints(sAggregratedPointers); 714157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka final int size = sAggregratedPointers.getPointerSize(); 715157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (size > sLastRecognitionPointSize 71680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) { 717157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka sLastRecognitionPointSize = size; 718157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka sLastRecognitionTime = eventTime; 719157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (DEBUG_LISTENER) { 72058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", 72158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, size)); 722157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka } 723157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mListener.onUpdateBatchInput(sAggregratedPointers); 7246c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7256c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7269580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 727f0e83046f022b5594f98aef07fbda7f2f837f262Tadashi G. Takaoka final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; 728f0e83046f022b5594f98aef07fbda7f2f837f262Tadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); 7299580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7309580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 73129d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private void mayEndBatchInput(final long eventTime) { 7326c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka synchronized (sAggregratedPointers) { 733c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); 7346c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 7356c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (DEBUG_LISTENER) { 73658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", 73758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, sAggregratedPointers.getPointerSize())); 7386c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7396c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sInGesture = false; 7403623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.onEndBatchInput(eventTime); 7416c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mListener.onEndBatchInput(sAggregratedPointers); 7426c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7439580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 744350fab6dc4d4d4aec272056004cbb5c039f5bf37Tadashi G. Takaoka final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; 745350fab6dc4d4d4aec272056004cbb5c039f5bf37Tadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); 7469580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7479580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 748694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void processMotionEvent(final int action, final int x, final int y, final long eventTime, 749694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 7508ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka switch (action) { 7518ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 7528ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 7538ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onDownEvent(x, y, eventTime, handler); 7548ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 7558ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_UP: 7568ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 7578ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onUpEvent(x, y, eventTime); 7588ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 7598ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 7603314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka onMoveEvent(x, y, eventTime, null); 7618ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 7628ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 7638ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onCancelEvent(x, y, eventTime); 7648ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 7658ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 7668ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 7678ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 768694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onDownEvent(final int x, final int y, final long eventTime, 769694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 770694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 771dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 772694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 7731d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 774f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 77563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 776f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyboardActionListener(handler.getKeyboardActionListener()); 777f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 778baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 7798a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 780160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka if (deltaT < sParams.mTouchNoiseThresholdTime) { 781b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final int distance = getDistance(x, y, mLastX, mLastY); 782b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (distance < sParams.mTouchNoiseThresholdDistance) { 783faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 784b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onDownEvent:" 785b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " ignore potential noise: time=%d distance=%d", 786b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, deltaT, distance)); 7879bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 788b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka ResearchLogger.pointerTracker_onDownEvent(deltaT, distance * distance); 7899bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 790d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 791baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 792baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 793baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 794baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 795eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final Key key = getKeyOn(x, y); 796b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onActualDownEvent(x, y); 7976c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 7981d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 799e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null && key.isModifier()) { 8001d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 8011d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // tracked should be released. 8021d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.releaseAllPointers(eventTime); 8031d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8041d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.add(this); 8051d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8061d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 8076c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!sShouldHandleGesture) { 8086c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 8096c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 810b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka // A gesture should start only from the letter key. 811b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() 812b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka && !mIsShowingMoreKeysPanel && key != null && Keyboard.isLetterCode(key.mCode); 813b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (mIsDetectingGesture) { 814b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 8156c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sGestureFirstDownTime = eventTime; 8169580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 81758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime, 8183623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka sTimeRecorder.getLastLetterTypingTime()); 819eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 8201d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8211d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 822694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void onDownEventInternal(final int x, final int y, final long eventTime) { 823e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onDownKey(x, y, eventTime); 82467a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 82532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. 826160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mIsAllowedSlidingKeyInput = sParams.mSlidingKeyInputEnabled 827c9f203805ca23276fcdcdc79b9298bc1d413ad98Tadashi G. Takaoka || (key != null && key.isModifier()) 82832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka || mKeyDetector.alwaysAllowsSlidingInput(); 8291a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 830c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka mKeyAlreadyProcessed = false; 831f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 832e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 8331a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 834e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the new 8351a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 8362a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 837e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onDownKey(x, y, eventTime); 838e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 839996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 840e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 841e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 84229d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 8436a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 8446a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 8456a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 846694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startSlidingKeyInput(final Key key) { 847e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (!mIsInSlidingKeyInput) { 848f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = key.isModifier(); 849e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 850996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 851996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 852996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 853f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka private void resetSlidingKeyInput() { 854f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInput = false; 855f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier = false; 856f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka } 857f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka 8586c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onGestureMoveEvent(final int x, final int y, final long eventTime, 85902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final boolean isMajorEvent, final Key key) { 8606c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 8616c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (mIsDetectingGesture) { 86202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isMajorEvent); 8631645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka mayStartBatchInput(key); 864157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (sInGesture) { 865157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mayUpdateBatchInput(eventTime, key); 8669580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8679580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8689580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 8699580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 870694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) { 871694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_MOVE_EVENT) { 872dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 873694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 874694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyAlreadyProcessed) { 875e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 876694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 877baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 8786c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture && me != null) { 879eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Add historical points to gesture path. 880eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int pointerIndex = me.findPointerIndex(mPointerId); 881eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalSize = me.getHistorySize(); 882eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int h = 0; h < historicalSize; h++) { 883eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalX = (int)me.getHistoricalX(pointerIndex, h); 884eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalY = (int)me.getHistoricalY(pointerIndex, h); 885eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final long historicalTime = me.getHistoricalEventTime(h); 8866c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onGestureMoveEvent(historicalX, historicalY, historicalTime, 88702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka false /* isMajorEvent */, null); 888eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 889eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 890eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 8916c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onMoveEventInternal(x, y, eventTime); 8926c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 8936c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 8946c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onMoveEventInternal(final int x, final int y, final long eventTime) { 8958a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 8968a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 897e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key oldKey = mCurrentKey; 898e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onMoveKey(x, y); 899eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 9006c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture) { 9016c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // Register move event on gesture tracker. 90202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, key); 9036c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 904c9ba26994b946d35c375cd1cd9a6db2b23b3de7eTadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 9056c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 9066c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 9076c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 9086c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 909eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 910eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 911e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 912c0b5c9c43e5eb7a6ed768d56f462ca9ed5c5f913Tadashi G. Takaoka if (oldKey == null) { 9139e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 9149e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 9151a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 916e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the 9171a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // new keyboard layout. 9182a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 919e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onMoveKey(x, y); 920e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 921e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 922e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 92329d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 924b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } else if (isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, key)) { 9259e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 9269e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 9279e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onPress() to notify that the new key is being pressed. 928e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 929e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 930996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 9312321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 932e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 93367a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 9341a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 935e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update key according 9361a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // to the new keyboard layout. 9372a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 938e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onMoveKey(x, y); 939e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 940e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 941e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 94229d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 94367a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 944b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be reported as a sudden 945b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // move by touch panel firmware. This hack detects such cases and translates the 946faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move event to successive up and down events. 947c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka // TODO: Should find a way to balance gesture detection and this hack. 948d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka if (sNeedsPhantomSuddenMoveEventHack 949b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) { 950d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka if (DEBUG_MODE) { 951b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 952b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " phantom sudden move event (distance=%d) is translated to " 953b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, 954b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka getDistance(x, y, lastX, lastY), 955b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka lastX, lastY, Keyboard.printableCode(oldKey.mCode), 956b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka x, y, Keyboard.printableCode(key.mCode))); 957d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka } 958c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka // TODO: This should be moved to outside of this nested if-clause? 9599bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 9609bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); 9619bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 962630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 963faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 964b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 965b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // HACK: On some devices, quick successive proximate touches may be reported as 966b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // a bogus down-move-up event by touch panel firmware. This hack detects such 967b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // cases and breaks these events into separate up and down events. 968b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka else if (sNeedsProximateBogusDownMoveUpEventHack 969b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka && sTimeRecorder.isInFastTyping(eventTime) 970b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { 971b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (DEBUG_MODE) { 972d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 973d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 974b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final float radiusRatio = 975d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mBogusMoveEventDetector.getDistanceFromDownEvent(x, y) 976d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka / keyDiagonal; 977b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 978d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka + " bogus down-move-up event (raidus=%.2f key diagonal) is " 979b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " translated to up[%d,%d,%s]/down[%d,%d,%s] events", 980b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, radiusRatio, 981b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka lastX, lastY, Keyboard.printableCode(oldKey.mCode), 982b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka x, y, Keyboard.printableCode(key.mCode))); 983b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 984b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka onUpEventInternal(eventTime); 985b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 986faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } else { 9875e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // HACK: If there are currently multiple touches, register the key even if 9885e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // the finger slides off the key. This defends against noise from some 9895e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // touch panels when there are close multiple touches. 9905e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // Caveat: When in chording input mode with a modifier key, we don't use 9915e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // this hack. 9926c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (getActivePointerTrackerCount() > 1 && sPointerTrackerQueue != null 9936c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { 994b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (DEBUG_MODE) { 995b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 996b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " detected sliding finger while multi touching", 997b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId)); 998b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 999b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka onUpEvent(x, y, eventTime); 1000b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mKeyAlreadyProcessed = true; 10015e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka } 10026c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!mIsDetectingGesture) { 1003c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka mKeyAlreadyProcessed = true; 1004c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka } 1005e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 1006faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } 100767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 1008c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 10096a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 1010b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, key)) { 10119e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 10129e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // notify that the previous key has been released. 1013e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 1014e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 1015996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 101698b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 101767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 1018e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 101967a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 10206c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!mIsDetectingGesture) { 1021c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka mKeyAlreadyProcessed = true; 1022c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka } 102367a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 102407221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 10256a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10266a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10276a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1028694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onUpEvent(final int x, final int y, final long eventTime) { 1029694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1030dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 1031694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 10321d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 10335c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 10341d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 10356c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!sInGesture) { 1036eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (mCurrentKey != null && mCurrentKey.isModifier()) { 1037eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Before processing an up event of modifier key, all pointers already being 1038eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // tracked should be released. 1039eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang queue.releaseAllPointersExcept(this, eventTime); 1040eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } else { 1041eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang queue.releaseAllPointersOlderThan(this, eventTime); 1042eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 10431d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 10441d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 1045630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 10466c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (queue != null) { 10476c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka queue.remove(this); 10486c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 10491d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 10501d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1051d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 1052d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 1053d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 10540cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 1055694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onPhantomUpEvent(final long eventTime) { 1056694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 10570cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime); 1058694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1059630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 1060d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 10611d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 10621d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1063630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka private void onUpEventInternal(final long eventTime) { 10642321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1065f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 10666c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIsDetectingGesture = false; 10676c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final Key currentKey = mCurrentKey; 10686c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 10695a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka // Release the last pressed key. 10706c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(currentKey); 10719d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 10729d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 10739d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 10749ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 1075eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 10766c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 10776c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null) { 10786c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka callListenerOnRelease(currentKey, currentKey.mCode, true); 1079eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 108029d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka mayEndBatchInput(eventTime); 1081eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 1082eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 108358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 1084694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyAlreadyProcessed) { 1085d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 1086694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 10876c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null && !currentKey.isRepeatable()) { 10883623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime); 10896a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10906a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10916a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1092694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) { 10939ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka onLongPressed(); 10949d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = true; 1095cc3500b0c8f11e8de1ad7376dda466d30637e462Tadashi G. Takaoka onDownEvent(x, y, SystemClock.uptimeMillis(), handler); 10969ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 10979ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 1098906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 1099d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 1100e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 11015c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 11021ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka if (queue != null) { 1103d00d963b9d47c1bba6f65534033a33fe7c30dde5Tadashi G. Takaoka queue.remove(this); 11041ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka } 1105d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 1106d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 1107694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onCancelEvent(final int x, final int y, final long eventTime) { 1108694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1109dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 1110694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 11111d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 11125c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 1113c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (queue != null) { 1114d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka queue.releaseAllPointersExcept(this, eventTime); 11151d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.remove(this); 1116c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 1117baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 11181d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 11191d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1120baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 11212321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 1122e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 1123f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka resetSlidingKeyInput(); 11249d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 11259d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 11269d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 11279ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 11286a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11296a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1130694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startRepeatKey(final Key key) { 11316c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (key != null && key.isRepeatable() && !sInGesture) { 11326662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv onRegisterKey(key); 1133a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(this); 1134a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1135a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1136a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 1137694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onRegisterKey(final Key key) { 1138c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka if (key != null) { 11393623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis()); 1140d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 1141c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 11426a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11436a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1144b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, 1145b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final Key newKey) { 1146694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyDetector == null) { 1147a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 1148694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1149694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final Key curKey = mCurrentKey; 11506a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 1151e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 1152e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } else if (curKey != null) { 1153f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( 1154f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInputFromModifier); 1155b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); 1156b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { 1157b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (DEBUG_MODE) { 1158d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared) 1159d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka / mKeyboard.mMostCommonKeyWidth; 1160b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1161d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka +" %.2f key width from key edge", 1162b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, distanceToEdgeRatio)); 1163b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1164b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return true; 1165b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1166b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput 1167b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka && sTimeRecorder.isInFastTyping(eventTime) 1168d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) { 1169b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (DEBUG_MODE) { 1170d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 1171d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 1172b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final float lengthFromDownRatio = 1173d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal; 1174b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1175d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka + " %.2f key diagonal from virtual down point", 1176b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, lengthFromDownRatio)); 1177b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1178b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return true; 1179b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1180b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return false; 1181b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } else { // curKey == null && newKey != null 1182e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 11836a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11846a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11856a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1186694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startLongPressTimer(final Key key) { 11876c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (key != null && key.isLongPressEnabled() && !sInGesture) { 1188a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startLongPressTimer(this); 11894189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 119066e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 119166e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 11923623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) { 119383e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 11948aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 1195dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 1196dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 119766e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 1198694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final int code = key.mCode; 11993623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka callListenerOnCodeInput(key, code, x, y, eventTime); 12002013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka callListenerOnRelease(key, code, false); 12016a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 12026a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1203694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void printTouchEvent(final String title, final int x, final int y, 1204694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final long eventTime) { 1205723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka final Key key = mKeyDetector.detectHitKey(x, y); 1206e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka final String code = KeyDetector.printableCode(key); 120758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, 120858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka (mKeyAlreadyProcessed ? "-" : " "), title, x, y, eventTime, code)); 1209dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 12106e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 1211