PointerTracker.java revision a28a05e971cc242b338331a3b78276fa95188d19
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; 26c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints; 2772934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 285f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils; 29f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 30faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 315509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport com.android.inputmethod.latin.R; 329bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 336b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 346a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 355c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 36dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 37a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class PointerTracker implements PointerTrackerQueue.Element { 38dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 39dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 40dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 41dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 42faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG; 4340a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 440657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka /** True if {@link PointerTracker}s should handle gesture events. */ 450657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka private static boolean sShouldHandleGesture = false; 468335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sMainDictionaryAvailable = false; 478335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByInputField = false; 488335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByUser = false; 499f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka private static boolean sGestureOffWhileFastTyping = 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(); 889f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka public void startGestureOffWhileFastTypingTimer(); 89a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker); 90a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker); 91a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code); 9298b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer(); 930ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer(); 94beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer(); 950ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout(); 962321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelKeyTimers(); 9729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 9829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static class Adapter implements TimerProxy { 9929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 100d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey) {} 10193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 10273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { return false; } 10393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 1049f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka public void startGestureOffWhileFastTypingTimer() {} 1059f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka @Override 106a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker) {} 10729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 108a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker) {} 109a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 110a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code) {} 11129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 11229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelLongPressTimer() {} 11329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 1140ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer() {} 1150ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 116beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer() {} 117beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 1180ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout() { return false; } 1190ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 12029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void cancelKeyTimers() {} 12129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 1222321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka } 1232321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka 124a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka static final class PointerTrackerParams { 1255509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final boolean mSlidingKeyInputEnabled; 1265509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final int mTouchNoiseThresholdTime; 1275509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final float mTouchNoiseThresholdDistance; 1285509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final int mTouchNoiseThresholdDistanceSquared; 1295509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1305509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); 1315509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1325509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private PointerTrackerParams() { 1335509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = false; 1345509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = 0; 1355509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdDistance = 0.0f; 1365509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdDistanceSquared = 0; 1375509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1385509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1395509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public PointerTrackerParams(TypedArray mainKeyboardViewAttr) { 1405509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean( 1415509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_slidingKeyInputEnable, false); 1425509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( 1435509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); 1445509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka final float touchNouseThresholdDistance = mainKeyboardViewAttr.getDimension( 1455509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); 1465509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdDistance = touchNouseThresholdDistance; 1475509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdDistanceSquared = 1485509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka (int)(touchNouseThresholdDistance * touchNouseThresholdDistance); 1495509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1505509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 1515509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 152160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka // Parameters for pointer handling. 1535509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private static PointerTrackerParams sParams; 154d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka private static boolean sNeedsPhantomSuddenMoveEventHack; 1555c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1565f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); 1575c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static PointerTrackerQueue sPointerTrackerQueue; 1585c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1595c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 1606a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1610efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 1620efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 163a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 164dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private KeyboardActionListener mListener = EMPTY_LISTENER; 165baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1665a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 167faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private int mKeyQuarterWidthSquared; 1686a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1696c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private boolean mIsDetectingGesture = false; // per PointerTracker. 1706c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static boolean sInGesture = false; 1716c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static long sGestureFirstDownTime; 172630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka private static long sLastLetterTypingUpTime; 1736c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static final InputPointers sAggregratedPointers = new InputPointers( 1746c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka GestureStroke.DEFAULT_CAPACITY); 1756c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static int sLastRecognitionPointSize = 0; 1766c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static long sLastRecognitionTime = 0; 1779580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 1788a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 1798a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 1808a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 1818a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 182e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The current key where this pointer is. 183e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mCurrentKey = null; 184e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The position where the current key was recognized for the first time. 1858a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 1868a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 1878a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 1888a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 1898a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 1908a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 1916a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1921a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 1931a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 1941a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 1959ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka // true if event is already translated to a key action. 196c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka private boolean mKeyAlreadyProcessed; 197c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 1989d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka // true if this pointer has been long-pressed and is showing a more keys panel. 1999d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private boolean mIsShowingMoreKeysPanel; 2009ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 201cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka // true if this pointer is in sliding key input 2025c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 203cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 20467a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // true if sliding key is allowed. 20567a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 20667a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 207996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka // ignore modifier key if true 208996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka private boolean mIgnoreModifierKey; 209996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 210dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Empty {@link KeyboardActionListener} 211e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka private static final KeyboardActionListener EMPTY_LISTENER = 212e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka new KeyboardActionListener.Adapter(); 2136e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka 214c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; 215f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 216d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka public static void init(boolean hasDistinctMultitouch, 21762b8dddb6ddb057555a1665759f9cf197e480c9fTadashi G. Takaoka boolean needsPhantomSuddenMoveEventHack) { 2185c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (hasDistinctMultitouch) { 2195c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = new PointerTrackerQueue(); 2205c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } else { 2215c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = null; 2225c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 223d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack; 2245509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = PointerTrackerParams.DEFAULT; 225160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 22693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 2275509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public static void setParameters(final TypedArray mainKeyboardViewAttr) { 2285509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka sParams = new PointerTrackerParams(mainKeyboardViewAttr); 2296a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 2306a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 2318335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static void updateGestureHandlingMode() { 2328335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sShouldHandleGesture = sMainDictionaryAvailable 2339f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka && !sGestureOffWhileFastTyping 2348335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByInputField 2358335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByUser 2368335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); 2378335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 2388335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 2398335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 240694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 2418335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sMainDictionaryAvailable = mainDictionaryAvailable; 2428335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 2438335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 2448335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 245694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 2468335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; 2478335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 248918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka } 249918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 2509f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka public static void setGestureOffWhileFastTyping() { 2519f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka sGestureOffWhileFastTyping = true; 2529f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka updateGestureHandlingMode(); 2539f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka } 2549f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka 2559f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka public static void clearGestureOffWhileFastTyping() { 2569f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka sGestureOffWhileFastTyping = false; 2579f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka updateGestureHandlingMode(); 2589f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka } 2599f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka 260694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, final KeyEventHandler handler) { 261b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka final ArrayList<PointerTracker> trackers = sTrackers; 2625c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2635c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 2645c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 2655c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 2665c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 2675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2685c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2695c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 2705c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2715c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2725c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 2735c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return sPointerTrackerQueue != null ? sPointerTrackerQueue.isAnyInSlidingKeyInput() : false; 2745c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 276694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyboardActionListener(final KeyboardActionListener listener) { 277afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 278afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 279afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 2805c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 2815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2825c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2835c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 284694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyDetector(final KeyDetector keyDetector) { 285afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 286afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 287afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 2885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 2895c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 2905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 2915c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 292918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 2938335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput(); 2948335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 2955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2965c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 297dde36ef34329164cf8b8a3985c578dab0343b3ebTadashi G. Takaoka public static void setReleasedKeyGraphicsToAllKeys() { 298afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 299afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 300afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 301e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.mCurrentKey); 3025c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3035c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 3045c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 305694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private PointerTracker(final int id, final KeyEventHandler handler) { 306694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (handler == null) { 3075c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 308694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 3095c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 310c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(id); 3115c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 3125c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 3135c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 3145c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 3156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3171a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 318694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key) { 3196c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 320eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return false; 321eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 322e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); 323e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 3247dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka Log.d(TAG, "onPress : " + KeyDetector.printableCode(key) 3252a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka + " ignoreModifier=" + ignoreModifierKey 326e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka + " enabled=" + key.isEnabled()); 327e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 32893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (ignoreModifierKey) { 329996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 33093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 331e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 3322a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onPressKey(key.mCode); 333690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 334690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 335d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 336690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 337690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 338690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 339dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 340dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 341690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 342690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 343694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, 344694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final int y) { 345e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); 3466bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 34729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int code = altersCode ? key.getAltCode() : primaryCode; 3482013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (DEBUG_LISTENER) { 34929d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) 35029d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka + " text=" + key.getOutputText() + " x=" + x + " y=" + y 3516bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode 352e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka + " enabled=" + key.isEnabled()); 3532013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 3549bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 3559bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, 3569bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge altersCode, code); 3579bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 358e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 359996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 360e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 3616bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 3626bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.isEnabled() || altersCode) { 3638cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka if (code == Keyboard.CODE_OUTPUT_TEXT) { 36429d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka mListener.onTextInput(key.getOutputText()); 3659f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka mTimerProxy.startGestureOffWhileFastTypingTimer(); 3668cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka } else if (code != Keyboard.CODE_UNSPECIFIED) { 367ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mListener.onCodeInput(code, x, y); 3689f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka mTimerProxy.startGestureOffWhileFastTypingTimer(); 3692013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 37093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 371dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 372dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 373690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 374690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 375694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnRelease(final Key key, final int primaryCode, 376694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final boolean withSliding) { 3776c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 378eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 379eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 380e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); 381e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 3827dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka Log.d(TAG, "onRelease : " + Keyboard.printableCode(primaryCode) 383e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey 384e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka + " enabled="+ key.isEnabled()); 385e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 3869bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 3879bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, 3889bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ignoreModifierKey); 3899bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 390e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 391996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 392e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 39393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (key.isEnabled()) { 3942a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onReleaseKey(primaryCode, withSliding); 39593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 396dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 397dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 3988aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 399694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_LISTENER) { 4008aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka Log.d(TAG, "onCancelInput"); 401694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 4029bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4039bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCancelInput(); 4049bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 4058aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 406dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 407dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 408694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setKeyDetectorInner(final KeyDetector keyDetector) { 409a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 4105a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 411c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.setKeyboardGeometry(mKeyboard.mMostCommonKeyWidth); 4128a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); 4138a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (newKey != mCurrentKey) { 4148a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (mDrawingProxy != null) { 4158a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 4168a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 41744972bcdb6f6dd0e4f02a26f31c7effaf0525403Tadashi G. Takaoka // Keep {@link #mCurrentKey} that comes from previous keyboard. 4188a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 4198da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4; 420faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; 4215a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 4225a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 4230cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 424cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 425cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 426cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 427cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 428e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKey() { 429e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey; 430dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 431dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 4320cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 4332aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 434e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey != null && mCurrentKey.isModifier(); 4352aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 4362aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 437694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public Key getKeyOn(final int x, final int y) { 438723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 4392aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 4402aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 441694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setReleasedKeyGraphics(final Key key) { 442d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 4436bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 444faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 445faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 446faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 4476bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, update the key release graphics just in case. 448faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(key); 449faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 450faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 451faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 452faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 453faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(shiftKey); 4542013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4552013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 456faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 4572013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 458faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.altCodeWhileTyping()) { 45929d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 460faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 461faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 462faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(altKey); 463faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 464faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 46529d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 466faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(k); 4672013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4682013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4696a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4706a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4716a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 472694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setPressedKeyGraphics(final Key key) { 4736bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 4746bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka return; 4756bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 4766bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka 4776bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 4786bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 4796bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; 4806bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (!needsToUpdateGraphics) { 481faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 482faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 483faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 4846c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!key.noKeyPreview() && !sInGesture) { 485faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.showKeyPreview(this); 486faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 487faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(key); 488faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 489faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 490faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 491faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 492faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(shiftKey); 4932013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4942013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 495faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 4962013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 49773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) { 49829d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 499faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 500faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 501faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(altKey); 502faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 503faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 50429d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 505faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(k); 5062013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5072013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 508d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 509c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 510c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 511694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updateReleaseKeyGraphics(final Key key) { 512faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onReleased(); 513faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 514faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 515faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 516694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void updatePressKeyGraphics(final Key key) { 517faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onPressed(); 518faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 519faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 520faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 521c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { 522c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka return mGestureStrokeWithPreviewPoints; 5232f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 5242f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang 5258a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastX() { 5268a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastX; 5278a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5288a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 5298a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastY() { 5308a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastY; 5318a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5328a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 5338a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 5348a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 5358a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5368a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 537694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onDownKey(final int x, final int y, final long eventTime) { 5388a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 5398a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 5408a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5418a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 542694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKeyInternal(final int x, final int y) { 5438a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 5448a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 545723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 5468a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5478a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 548694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKey(final int x, final int y) { 5498a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 5508a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5518a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 552694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveToNewKey(final Key newKey, final int x, final int y) { 553e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mCurrentKey = newKey; 5548a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 5558a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 556e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return newKey; 5578a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5588a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 5596c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static int getActivePointerTrackerCount() { 5606c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return (sPointerTrackerQueue == null) ? 1 : sPointerTrackerQueue.size(); 5616c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 5626c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 5631645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka private void mayStartBatchInput(final Key key) { 564c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { 5659c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka return; 5669c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka } 5671645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka if (key == null || !Character.isLetter(key.mCode)) { 5681645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka return; 5691645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka } 5709c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka if (DEBUG_LISTENER) { 5719c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka Log.d(TAG, "onStartBatchInput"); 5729580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5739c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka sInGesture = true; 5749c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka mListener.onStartBatchInput(); 575350fab6dc4d4d4aec272056004cbb5c039f5bf37Tadashi G. Takaoka final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; 576350fab6dc4d4d4aec272056004cbb5c039f5bf37Tadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); 5776c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 5786c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 579157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka private void mayUpdateBatchInput(final long eventTime, final Key key) { 580157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (key != null) { 581157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka synchronized (sAggregratedPointers) { 582157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.appendIncrementalBatchPoints(sAggregratedPointers); 583157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka final int size = sAggregratedPointers.getPointerSize(); 584157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (size > sLastRecognitionPointSize 585157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka && GestureStroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) { 586157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka sLastRecognitionPointSize = size; 587157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka sLastRecognitionTime = eventTime; 588157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (DEBUG_LISTENER) { 589157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka Log.d(TAG, "onUpdateBatchInput: batchPoints=" + size); 590157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka } 591157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mListener.onUpdateBatchInput(sAggregratedPointers); 5926c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 5936c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 5949580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 595f0e83046f022b5594f98aef07fbda7f2f837f262Tadashi G. Takaoka final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; 596f0e83046f022b5594f98aef07fbda7f2f837f262Tadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); 5979580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5989580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 599c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka private void mayEndBatchInput() { 6006c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka synchronized (sAggregratedPointers) { 601c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); 602c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.reset(); 6036c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 6046c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (DEBUG_LISTENER) { 6056c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka Log.d(TAG, "onEndBatchInput: batchPoints=" 6066c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka + sAggregratedPointers.getPointerSize()); 6076c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 6086c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sInGesture = false; 6096c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mListener.onEndBatchInput(sAggregratedPointers); 6106c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka clearBatchInputPointsOfAllPointerTrackers(); 6116c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 6129580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 613350fab6dc4d4d4aec272056004cbb5c039f5bf37Tadashi G. Takaoka final boolean isOldestTracker = sPointerTrackerQueue.getOldestElement() == this; 614350fab6dc4d4d4aec272056004cbb5c039f5bf37Tadashi G. Takaoka mDrawingProxy.showGesturePreviewTrail(this, isOldestTracker); 6159580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 6169580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 6176c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static void abortBatchInput() { 6181e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka clearBatchInputPointsOfAllPointerTrackers(); 6191e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka } 6201e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka 6216c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static void clearBatchInputPointsOfAllPointerTrackers() { 6226c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int trackersSize = sTrackers.size(); 6236c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka for (int i = 0; i < trackersSize; ++i) { 6246c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final PointerTracker tracker = sTrackers.get(i); 625c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka tracker.mGestureStrokeWithPreviewPoints.reset(); 6269580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 6276c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sAggregratedPointers.reset(); 6286c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sLastRecognitionPointSize = 0; 6296c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sLastRecognitionTime = 0; 6309580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 6319580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 632694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void processMotionEvent(final int action, final int x, final int y, final long eventTime, 633694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 6348ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka switch (action) { 6358ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 6368ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 6378ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onDownEvent(x, y, eventTime, handler); 6388ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6398ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_UP: 6408ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 6418ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onUpEvent(x, y, eventTime); 6428ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6438ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 6443314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka onMoveEvent(x, y, eventTime, null); 6458ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6468ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 6478ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onCancelEvent(x, y, eventTime); 6488ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6498ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 6508ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 6518ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 652694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onDownEvent(final int x, final int y, final long eventTime, 653694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final KeyEventHandler handler) { 654694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 655dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 656694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 6571d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 658f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 65963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 660f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyboardActionListener(handler.getKeyboardActionListener()); 661f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 662baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 6638a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 664160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka if (deltaT < sParams.mTouchNoiseThresholdTime) { 6658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int dx = x - mLastX; 6668a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int dy = y - mLastY; 667baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka final int distanceSquared = (dx * dx + dy * dy); 6685509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka if (distanceSquared < sParams.mTouchNoiseThresholdDistanceSquared) { 669faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 670faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT 671faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka + " distance=" + distanceSquared); 6729bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 6739bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_onDownEvent(deltaT, distanceSquared); 6749bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 675d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 676baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 677baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 678baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 679baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 680eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final Key key = getKeyOn(x, y); 6816c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 6821d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 683e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null && key.isModifier()) { 6841d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 6851d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // tracked should be released. 6861d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.releaseAllPointers(eventTime); 6871d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 6881d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.add(this); 6891d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 6901d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 6916c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!sShouldHandleGesture) { 6926c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 6936c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 694b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka // A gesture should start only from the letter key. 695b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() 696b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka && !mIsShowingMoreKeysPanel && key != null && Keyboard.isLetterCode(key.mCode); 697b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (mIsDetectingGesture) { 698b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (getActivePointerTrackerCount() == 1) { 6996c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka sGestureFirstDownTime = eventTime; 7009580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 701c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka onGestureDownEvent(x, y, eventTime); 702eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 7031d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 7041d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 705c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka private void onGestureDownEvent(final int x, final int y, final long eventTime) { 706c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mIsDetectingGesture = true; 707630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka mGestureStrokeWithPreviewPoints.setLastLetterTypingTime(eventTime, sLastLetterTypingUpTime); 708c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka final int elapsedTimeFromFirstDown = (int)(eventTime - sGestureFirstDownTime); 709c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mGestureStrokeWithPreviewPoints.addPoint(x, y, elapsedTimeFromFirstDown, 71002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka true /* isMajorEvent */); 711c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka } 712c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka 713694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void onDownEventInternal(final int x, final int y, final long eventTime) { 714e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onDownKey(x, y, eventTime); 71567a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 71632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. 717160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mIsAllowedSlidingKeyInput = sParams.mSlidingKeyInputEnabled 718c9f203805ca23276fcdcdc79b9298bc1d413ad98Tadashi G. Takaoka || (key != null && key.isModifier()) 71932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka || mKeyDetector.alwaysAllowsSlidingInput(); 7201a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 721c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka mKeyAlreadyProcessed = false; 722cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 723996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIgnoreModifierKey = false; 724e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 7251a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 726e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the new 7271a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 7282a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 729e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onDownKey(x, y, eventTime); 730e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 731996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 732e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 733e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 734e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setPressedKeyGraphics(key); 7356a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7366a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7376a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 738694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startSlidingKeyInput(final Key key) { 739e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (!mIsInSlidingKeyInput) { 740e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mIgnoreModifierKey = key.isModifier(); 741e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 742996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 743996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 744996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 7456c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onGestureMoveEvent(final int x, final int y, final long eventTime, 74602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final boolean isMajorEvent, final Key key) { 7476c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int gestureTime = (int)(eventTime - sGestureFirstDownTime); 7486c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (mIsDetectingGesture) { 74902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mGestureStrokeWithPreviewPoints.addPoint(x, y, gestureTime, isMajorEvent); 7501645902cce7eaceff4aba3ea01d723240c6ce189Tadashi G. Takaoka mayStartBatchInput(key); 751157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka if (sInGesture) { 752157fe98fd439a7d9cc063a7f5573f688e33c2f29Tadashi G. Takaoka mayUpdateBatchInput(eventTime, key); 7539580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7549580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7559580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7569580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 757694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) { 758694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_MOVE_EVENT) { 759dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 760694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 761694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyAlreadyProcessed) { 762e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 763694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 764baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 7656c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture && me != null) { 766eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Add historical points to gesture path. 767eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int pointerIndex = me.findPointerIndex(mPointerId); 768eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalSize = me.getHistorySize(); 769eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int h = 0; h < historicalSize; h++) { 770eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalX = (int)me.getHistoricalX(pointerIndex, h); 771eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalY = (int)me.getHistoricalY(pointerIndex, h); 772eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final long historicalTime = me.getHistoricalEventTime(h); 7736c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onGestureMoveEvent(historicalX, historicalY, historicalTime, 77402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka false /* isMajorEvent */, null); 775eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 776eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 777eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 7786c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onMoveEventInternal(x, y, eventTime); 7796c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7806c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 7816c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onMoveEventInternal(final int x, final int y, final long eventTime) { 7828a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 7838a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 784e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key oldKey = mCurrentKey; 785e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onMoveKey(x, y); 786eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 7876c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sShouldHandleGesture) { 7886c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // Register move event on gesture tracker. 78902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, key); 7906c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 7916c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIgnoreModifierKey = true; 7926c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 7936c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIsInSlidingKeyInput = true; 7946c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 7956c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 7966c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 7976c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 798eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 799eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 800e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 801c0b5c9c43e5eb7a6ed768d56f462ca9ed5c5f913Tadashi G. Takaoka if (oldKey == null) { 8029e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 8039e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 8041a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 805e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the 8061a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // new keyboard layout. 8072a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 808e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onMoveKey(x, y); 809e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 810e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 811e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 812e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setPressedKeyGraphics(key); 813e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } else if (isMajorEnoughMoveToBeOnNewKey(x, y, key)) { 8149e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 8159e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 8169e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onPress() to notify that the new key is being pressed. 817e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 818e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 819996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 8202321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 821e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 82267a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 8231a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 824e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update key according 8251a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // to the new keyboard layout. 8262a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 827e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onMoveKey(x, y); 828e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 829e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 830e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 831e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setPressedKeyGraphics(key); 83267a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 833faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be translated to sudden 834faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move by touch panel firmware. This hack detects the case and translates the 835faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move event to successive up and down events. 836faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int dx = x - lastX; 837faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int dy = y - lastY; 838faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int lastMoveSquared = dx * dx + dy * dy; 839c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka // TODO: Should find a way to balance gesture detection and this hack. 840d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka if (sNeedsPhantomSuddenMoveEventHack 841c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka && lastMoveSquared >= mKeyQuarterWidthSquared 8426c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka && !mIsDetectingGesture) { 843d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka if (DEBUG_MODE) { 844d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka Log.w(TAG, String.format("onMoveEvent:" 845d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka + " phantom sudden move event is translated to " 846faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); 847d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka } 848c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka // TODO: This should be moved to outside of this nested if-clause? 8499bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 8509bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); 8519bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 852630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 853faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 854faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } else { 8555e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // HACK: If there are currently multiple touches, register the key even if 8565e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // the finger slides off the key. This defends against noise from some 8575e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // touch panels when there are close multiple touches. 8585e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // Caveat: When in chording input mode with a modifier key, we don't use 8595e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // this hack. 8606c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (getActivePointerTrackerCount() > 1 && sPointerTrackerQueue != null 8616c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { 862630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 8635e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka } 8646c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!mIsDetectingGesture) { 865c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka mKeyAlreadyProcessed = true; 866c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka } 867e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 868faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } 86967a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 870c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 8716a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 872e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, key)) { 8739e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 8749e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // notify that the previous key has been released. 875e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 876e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 877996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 87898b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 87967a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 880e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 88167a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 8826c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!mIsDetectingGesture) { 883c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka mKeyAlreadyProcessed = true; 884c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka } 88567a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 88607221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 8876a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 8886a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 8896a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 890694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onUpEvent(final int x, final int y, final long eventTime) { 891694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 892dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 893694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 8941d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 8955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 8961d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 8976c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (!sInGesture) { 898eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (mCurrentKey != null && mCurrentKey.isModifier()) { 899eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Before processing an up event of modifier key, all pointers already being 900eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // tracked should be released. 901eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang queue.releaseAllPointersExcept(this, eventTime); 902eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } else { 903eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang queue.releaseAllPointersOlderThan(this, eventTime); 904eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 9051d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9061d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 907630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 9086c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (queue != null) { 9096c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka queue.remove(this); 9106c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 9111d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9121d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 913d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 914d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 915d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 9160cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 917694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onPhantomUpEvent(final long eventTime) { 918694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 9190cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime); 920694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 921630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka onUpEventInternal(eventTime); 922d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 9231d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9241d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 925630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka private void onUpEventInternal(final long eventTime) { 9262321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 927cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 9286c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIsDetectingGesture = false; 9296c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final Key currentKey = mCurrentKey; 9306c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 9315a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka // Release the last pressed key. 9326c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka setReleasedKeyGraphics(currentKey); 9339d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 9349d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 9359d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 9369ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 937eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 9386c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 9396c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null) { 9406c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka callListenerOnRelease(currentKey, currentKey.mCode, true); 941eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 942c7dc673cf0fb56015826079423ced659b9180febTadashi G. Takaoka mayEndBatchInput(); 943eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 944eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 9456c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // This event will be recognized as a regular code input. Clear unused possible batch points 9466c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // so they are not mistakenly displayed as preview. 9470c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang clearBatchInputPointsOfAllPointerTrackers(); 948694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyAlreadyProcessed) { 949d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 950694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 9516c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null && !currentKey.isRepeatable()) { 9526c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka detectAndSendKey(currentKey, mKeyX, mKeyY); 953630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka final int code = currentKey.mCode; 954630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka if (Keyboard.isLetterCode(code) && code != Keyboard.CODE_SPACE) { 955630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka sLastLetterTypingUpTime = eventTime; 956630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 9576a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9586a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9596a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 960694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onShowMoreKeysPanel(final int x, final int y, final KeyEventHandler handler) { 9611e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka abortBatchInput(); 9629ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka onLongPressed(); 9639d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = true; 964cc3500b0c8f11e8de1ad7376dda466d30637e462Tadashi G. Takaoka onDownEvent(x, y, SystemClock.uptimeMillis(), handler); 9659ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 9669ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 967906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 968d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 969e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 9705c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 9711ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka if (queue != null) { 972d00d963b9d47c1bba6f65534033a33fe7c30dde5Tadashi G. Takaoka queue.remove(this); 9731ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka } 974d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 975d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 976694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onCancelEvent(final int x, final int y, final long eventTime) { 977694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 978dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 979694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 9801d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 9815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 982c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (queue != null) { 983d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka queue.releaseAllPointersExcept(this, eventTime); 9841d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.remove(this); 985c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 986baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 9871d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9881d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 989baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 9902321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 991e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 992cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 9939d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 9949d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 9959d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 9969ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 9976a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9986a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 999694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startRepeatKey(final Key key) { 10006c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (key != null && key.isRepeatable() && !sInGesture) { 10016662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv onRegisterKey(key); 1002a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(this); 1003a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1004a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 1005a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 1006694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onRegisterKey(final Key key) { 1007c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka if (key != null) { 1008e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka detectAndSendKey(key, key.mX, key.mY); 1009d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 1010c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 10116a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10126a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1013694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final Key newKey) { 1014694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (mKeyDetector == null) { 1015a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 1016694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 1017694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final Key curKey = mCurrentKey; 10186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 1019e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 1020e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } else if (curKey != null) { 1021e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return curKey.squaredDistanceToEdge(x, y) 1022a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka >= mKeyDetector.getKeyHysteresisDistanceSquared(); 10236a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 1024e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 10256a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10266a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10276a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1028694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startLongPressTimer(final Key key) { 10296c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (key != null && key.isLongPressEnabled() && !sInGesture) { 1030a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startLongPressTimer(this); 10314189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 103266e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 103366e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 1034694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void detectAndSendKey(final Key key, final int x, final int y) { 103583e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 10368aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 1037dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 1038dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 103966e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 1040694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final int code = key.mCode; 1041ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok callListenerOnCodeInput(key, code, x, y); 10422013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka callListenerOnRelease(key, code, false); 10436a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10446a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1045694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void printTouchEvent(final String title, final int x, final int y, 1046694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final long eventTime) { 1047723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka final Key key = mKeyDetector.detectHitKey(x, y); 1048e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka final String code = KeyDetector.printableCode(key); 1049e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title, 1050d7edd1cbb5dfacacdd39766e379fb60d2b7c6b73Tadashi G. Takaoka (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, eventTime, code)); 1051dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 10526e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 1053