PointerTracker.java revision 8335c59ea7715f3dbc6625f128a7a038f314a89f
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 194daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport android.graphics.Canvas; 204daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport android.graphics.Paint; 21e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaokaimport android.os.SystemClock; 22c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport android.util.Log; 238ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaokaimport android.view.MotionEvent; 24fe824948bb5c07dcd0a47221cb5b7b4f2f4365caTadashi G. Takaokaimport android.view.View; 254692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaokaimport android.widget.TextView; 26c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 27918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 28f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStroke; 2972934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 30f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 31faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 328335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaokaimport com.android.inputmethod.latin.Utils; 339bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 346b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 356a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 365c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 37dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 387ae1fd02d40c8c026a411f1037753725868c611eTadashi G. Takaokapublic class PointerTracker implements PointerTrackerQueue.Element { 39dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 40dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 41dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 42dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 43faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG; 4440a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 450657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka /** True if {@link PointerTracker}s should handle gesture events. */ 460657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka private static boolean sShouldHandleGesture = false; 478335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sMainDictionaryAvailable = false; 488335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByInputField = false; 498335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static boolean sGestureHandlingEnabledByUser = false; 50918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 511e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka private static final int MIN_GESTURE_RECOGNITION_TIME = 100; // msec 529580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 53f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public interface KeyEventHandler { 54f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 55f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyDetector object that is used for this PointerTracker. 56f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyDetector object that is used for this PointerTracker 57f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 58f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyDetector getKeyDetector(); 59f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 60f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 61f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyboardActionListener object that is used to register key code and so on. 62f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyboardActionListner for this PointerTracker 63f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 64f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener(); 65f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 66f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 67f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get DrawingProxy object that is used for this PointerTracker. 68f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the DrawingProxy object that is used for this PointerTracker 69f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 70f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy(); 71f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 72f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 73f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get TimerProxy object that handles key repeat and long press timer event for this 74f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * PointerTracker. 75f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the TimerProxy object that handles key repeat and long press timer event. 76f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 77f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public TimerProxy getTimerProxy(); 78f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 79f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 809d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public interface DrawingProxy extends MoreKeysPanel.Controller { 816a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public void invalidateKey(Key key); 824692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka public TextView inflateKeyPreviewText(); 83e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public void showKeyPreview(PointerTracker tracker); 84d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void dismissKeyPreview(PointerTracker tracker); 854daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang public void showGestureTrail(PointerTracker tracker); 866a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 876a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 882321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public interface TimerProxy { 89d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey); 9073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState(); 91a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker); 92a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker); 93a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code); 9498b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer(); 950ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer(); 96beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer(); 970ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout(); 982321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelKeyTimers(); 9929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 10029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static class Adapter implements TimerProxy { 10129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 102d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey) {} 10393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 10473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { return false; } 10593246652638f423d5220449f65495dea0639c750Tadashi 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 124160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka // Parameters for pointer handling. 125c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka private static MainKeyboardView.PointerTrackerParams sParams; 1265c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static int sTouchNoiseThresholdDistanceSquared; 127d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka private static boolean sNeedsPhantomSuddenMoveEventHack; 1285c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 129b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka private static final ArrayList<PointerTracker> sTrackers = new ArrayList<PointerTracker>(); 1300c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang private static final InputPointers sAggregratedPointers = new InputPointers( 1310c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang GestureStroke.DEFAULT_CAPACITY); 1325c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static PointerTrackerQueue sPointerTrackerQueue; 1331e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka // HACK: Change gesture detection criteria depending on this variable. 1341e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka // TODO: Find more comprehensive ways to detect a gesture start. 1351e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka // True when the previous user input was a gesture input, not a typing input. 1361e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka private static boolean sWasInGesture; 1375c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1385c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 1396a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1400efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 1410efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 142a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 143dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private KeyboardActionListener mListener = EMPTY_LISTENER; 144baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1455a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 146faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private int mKeyQuarterWidthSquared; 1474692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka private final TextView mKeyPreviewText; 1486a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1499580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private boolean mIsAlphabetKeyboard; 1509580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private boolean mIsPossibleGesture = false; 1519580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private boolean mInGesture = false; 1529580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 1531e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka // TODO: Remove these variables 1549580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private int mLastRecognitionPointSize = 0; 1559580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private long mLastRecognitionTime = 0; 1569580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 1578a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 1588a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 1598a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 1608a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 161e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The current key where this pointer is. 162e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mCurrentKey = null; 163e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The position where the current key was recognized for the first time. 1648a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 1658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 1668a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 1678a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 1688a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 1698a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 1706a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1711a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 1721a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 1731a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 1749ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka // true if event is already translated to a key action. 175c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka private boolean mKeyAlreadyProcessed; 176c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 1779d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka // true if this pointer has been long-pressed and is showing a more keys panel. 1789d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private boolean mIsShowingMoreKeysPanel; 1799ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 180cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka // true if this pointer is in sliding key input 1815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 182cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 18367a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // true if sliding key is allowed. 18467a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 18567a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 186996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka // ignore modifier key if true 187996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka private boolean mIgnoreModifierKey; 188996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 189dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Empty {@link KeyboardActionListener} 190e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka private static final KeyboardActionListener EMPTY_LISTENER = 191e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka new KeyboardActionListener.Adapter(); 1926e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka 193f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka private final GestureStroke mGestureStroke; 194f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 195d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka public static void init(boolean hasDistinctMultitouch, 19662b8dddb6ddb057555a1665759f9cf197e480c9fTadashi G. Takaoka boolean needsPhantomSuddenMoveEventHack) { 1975c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (hasDistinctMultitouch) { 1985c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = new PointerTrackerQueue(); 1995c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } else { 2005c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = null; 2015c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 202d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack; 2035c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 204c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka setParameters(MainKeyboardView.PointerTrackerParams.DEFAULT); 205160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 20693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 207c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka public static void setParameters(MainKeyboardView.PointerTrackerParams params) { 208160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka sParams = params; 2095c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sTouchNoiseThresholdDistanceSquared = (int)( 210160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka params.mTouchNoiseThresholdDistance * params.mTouchNoiseThresholdDistance); 2116a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 2126a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 2138335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka private static void updateGestureHandlingMode() { 2148335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sShouldHandleGesture = sMainDictionaryAvailable 2158335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByInputField 2168335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && sGestureHandlingEnabledByUser 2178335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); 2188335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 2198335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 2208335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 2218335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka public static void setMainDictionaryAvailability(boolean mainDictionaryAvailable) { 2228335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sMainDictionaryAvailable = mainDictionaryAvailable; 2238335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 2248335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 2258335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 2268335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka public static void setGestureHandlingEnabledByUser(boolean gestureHandlingEnabledByUser) { 2278335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; 2288335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 229918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka } 230918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 2315c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, KeyEventHandler handler) { 232b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka final ArrayList<PointerTracker> trackers = sTrackers; 2335c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2345c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 2355c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 2365c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 2375c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 2385c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2395c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2405c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 2415c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2425c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2435c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 2445c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return sPointerTrackerQueue != null ? sPointerTrackerQueue.isAnyInSlidingKeyInput() : false; 2455c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2465c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2475c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void setKeyboardActionListener(KeyboardActionListener listener) { 248afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 249afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 250afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 2515c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 2525c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2535c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2545c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2558335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka public static void setKeyDetector(KeyDetector keyDetector) { 256afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 257afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 258afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 2595c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 2605c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 2615c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 2625c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 263918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 2648335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput(); 2658335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka updateGestureHandlingMode(); 2665c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2685c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void dismissAllKeyPreviews() { 269afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 270afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 271afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 272fe824948bb5c07dcd0a47221cb5b7b4f2f4365caTadashi G. Takaoka tracker.getKeyPreviewText().setVisibility(View.INVISIBLE); 273e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.mCurrentKey); 2745c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2765c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2779580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // TODO: To handle multi-touch gestures we may want to move this method to 2789580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // {@link PointerTrackerQueue}. 2799580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private static InputPointers getIncrementalBatchPoints() { 280afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 281afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 282afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 2830c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang tracker.mGestureStroke.appendIncrementalBatchPoints(sAggregratedPointers); 284f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 2850c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang return sAggregratedPointers; 286f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 287f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 2889580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // TODO: To handle multi-touch gestures we may want to move this method to 2899580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // {@link PointerTrackerQueue}. 2909580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private static InputPointers getAllBatchPoints() { 291afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 292afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 293afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 2940c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang tracker.mGestureStroke.appendAllBatchPoints(sAggregratedPointers); 295f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 2960c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang return sAggregratedPointers; 297f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 298f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 2999580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // TODO: To handle multi-touch gestures we may want to move this method to 3009580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // {@link PointerTrackerQueue}. 3011e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka public static void clearBatchInputPointsOfAllPointerTrackers() { 302afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 303afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 304afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 3059580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka tracker.mGestureStroke.reset(); 306f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 3070c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang sAggregratedPointers.reset(); 308f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 309f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 310f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka private PointerTracker(int id, KeyEventHandler handler) { 3115c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (handler == null) 3125c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 3135c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 314f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka mGestureStroke = new GestureStroke(id); 3155c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 3165c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 3175c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 3185c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 3194692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka mKeyPreviewText = mDrawingProxy.inflateKeyPreviewText(); 3204692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka } 3214692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka 3224692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka public TextView getKeyPreviewText() { 3234692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka return mKeyPreviewText; 3246a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3256a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 3261a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 3272a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key) { 3289580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (mInGesture) { 329eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return false; 330eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 331e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); 332e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 3337dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka Log.d(TAG, "onPress : " + KeyDetector.printableCode(key) 3342a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka + " ignoreModifier=" + ignoreModifierKey 335e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka + " enabled=" + key.isEnabled()); 336e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 33793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (ignoreModifierKey) { 338996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 33993246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 340e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 3412a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onPressKey(key.mCode); 342690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 343690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 344d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 345690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 346690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 347690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 348dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 349dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 350690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 351690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 352ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok private void callListenerOnCodeInput(Key key, int primaryCode, int x, int y) { 353e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); 3546bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 3556bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final int code = altersCode ? key.mAltCode : primaryCode; 3562013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (DEBUG_LISTENER) { 3578cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) + " text=" + key.mOutputText 358ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok + " x=" + x + " y=" + y 3596bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode 360e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka + " enabled=" + key.isEnabled()); 3612013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 3629bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 3639bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, 3649bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge altersCode, code); 3659bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 366e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 367996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 368e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 3696bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 3706bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.isEnabled() || altersCode) { 3718cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka if (code == Keyboard.CODE_OUTPUT_TEXT) { 3728cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka mListener.onTextInput(key.mOutputText); 3738cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka } else if (code != Keyboard.CODE_UNSPECIFIED) { 374ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mListener.onCodeInput(code, x, y); 3752013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 37693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 377dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 378dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 379690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 380690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 381e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) { 3829580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (mInGesture) { 383eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 384eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 385e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); 386e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 3877dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka Log.d(TAG, "onRelease : " + Keyboard.printableCode(primaryCode) 388e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey 389e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka + " enabled="+ key.isEnabled()); 390e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 3919bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 3929bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, 3939bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ignoreModifierKey); 3949bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 395e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 396996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 397e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 39893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (key.isEnabled()) { 3992a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mListener.onReleaseKey(primaryCode, withSliding); 40093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 401dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 402dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 4038aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 404dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 4058aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka Log.d(TAG, "onCancelInput"); 4069bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4079bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_callListenerOnCancelInput(); 4089bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 4098aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 410dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 411dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 41246286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka private void setKeyDetectorInner(KeyDetector keyDetector) { 413a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 4145a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 4159580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mIsAlphabetKeyboard = mKeyboard.mId.isAlphabetKeyboard(); 416f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka mGestureStroke.setGestureSampleLength( 417f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 4188a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); 4198a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (newKey != mCurrentKey) { 4208a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (mDrawingProxy != null) { 4218a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 4228a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 42344972bcdb6f6dd0e4f02a26f31c7effaf0525403Tadashi G. Takaoka // Keep {@link #mCurrentKey} that comes from previous keyboard. 4248a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 4258da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4; 426faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; 4275a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 4285a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 4290cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 430cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 431cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 432cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 433cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 434e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKey() { 435e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey; 436dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 437dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 4380cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 4392aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 440e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey != null && mCurrentKey.isModifier(); 4412aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 4422aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 443e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKeyOn(int x, int y) { 444723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 4452aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 4462aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 447e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private void setReleasedKeyGraphics(Key key) { 448d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 4496bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 450faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 451faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 452faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 4536bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, update the key release graphics just in case. 454faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(key); 455faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 456faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 457faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 458faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 459faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(shiftKey); 4602013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4612013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 462faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 4632013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 464faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.altCodeWhileTyping()) { 465faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final int altCode = key.mAltCode; 466faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 467faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 468faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(altKey); 469faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 470faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 471faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (k != key && k.mAltCode == altCode) { 472faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updateReleaseKeyGraphics(k); 4732013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4742013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4756a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4766a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4776a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 478e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private void setPressedKeyGraphics(Key key) { 4796bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 4806bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka return; 4816bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 4826bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka 4836bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 4846bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); 4856bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; 4866bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (!needsToUpdateGraphics) { 487faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 488faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 489faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 4909580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (!key.noKeyPreview() && !mInGesture) { 491faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.showKeyPreview(this); 492faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 493faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(key); 494faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 495faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 496faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 497faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 498faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(shiftKey); 4992013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5002013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 501faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 5022013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 50373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) { 504faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final int altCode = key.mAltCode; 505faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 506faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 507faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(altKey); 508faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 509faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 510faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (k != key && k.mAltCode == altCode) { 511faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka updatePressKeyGraphics(k); 5122013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 5132013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 514d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 515c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 516c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 517faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka private void updateReleaseKeyGraphics(Key key) { 518faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onReleased(); 519faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 520faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 521faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 522faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka private void updatePressKeyGraphics(Key key) { 523faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka key.onPressed(); 524faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 525faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 526faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 5272f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang public void drawGestureTrail(Canvas canvas, Paint paint) { 5282f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang if (mInGesture) { 5292f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang mGestureStroke.drawGestureTrail(canvas, paint, mLastX, mLastY); 5302f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 5312f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 5322f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang 5338a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastX() { 5348a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastX; 5358a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5368a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 5378a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastY() { 5388a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastY; 5398a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5408a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 5418a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 5428a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 5438a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5448a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 545e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key onDownKey(int x, int y, long eventTime) { 5468a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 5478a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 5488a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5498a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 550e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key onMoveKeyInternal(int x, int y) { 5518a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 5528a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 553723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 5548a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5558a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 556e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key onMoveKey(int x, int y) { 5578a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 5588a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5598a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 560e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key onMoveToNewKey(Key newKey, int x, int y) { 561e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mCurrentKey = newKey; 5628a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 5638a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 564e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return newKey; 5658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5668a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 5679580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private void startBatchInput() { 5689580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (DEBUG_LISTENER) { 5699580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka Log.d(TAG, "onStartBatchInput"); 5709580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5719580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mInGesture = true; 5729580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mListener.onStartBatchInput(); 5739580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5749580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 5759580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private void updateBatchInput(InputPointers batchPoints) { 5769580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (DEBUG_LISTENER) { 5779580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize()); 5789580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5799580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mListener.onUpdateBatchInput(batchPoints); 5809580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5819580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 5829580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private void endBatchInput(InputPointers batchPoints) { 5839580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (DEBUG_LISTENER) { 5849580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka Log.d(TAG, "onEndBatchInput: batchPoints=" + batchPoints.getPointerSize()); 5859580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5869580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mListener.onEndBatchInput(batchPoints); 5871e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka clearBatchInputRecognitionStateOfThisPointerTracker(); 5881e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka clearBatchInputPointsOfAllPointerTrackers(); 5891e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka sWasInGesture = true; 5909580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5919580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 5929580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private void abortBatchInput() { 5931e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka clearBatchInputRecognitionStateOfThisPointerTracker(); 5941e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka clearBatchInputPointsOfAllPointerTrackers(); 5951e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka } 5961e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka 5971e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka private void clearBatchInputRecognitionStateOfThisPointerTracker() { 5989580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mIsPossibleGesture = false; 5999580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mInGesture = false; 6001e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka mLastRecognitionPointSize = 0; 6011e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka mLastRecognitionTime = 0; 6029580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 6039580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 6049580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private boolean updateBatchInputRecognitionState(long eventTime, int size) { 6059580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (size > mLastRecognitionPointSize 6061e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka && eventTime > mLastRecognitionTime + MIN_GESTURE_RECOGNITION_TIME) { 6079580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mLastRecognitionPointSize = size; 6089580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mLastRecognitionTime = eventTime; 6099580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka return true; 6109580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 6119580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka return false; 6129580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 6139580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 6148ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka public void processMotionEvent(int action, int x, int y, long eventTime, 6158ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka KeyEventHandler handler) { 6168ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka switch (action) { 6178ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 6188ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 6198ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onDownEvent(x, y, eventTime, handler); 6208ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6218ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_UP: 6228ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 6238ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onUpEvent(x, y, eventTime); 6248ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6258ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 6263314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka onMoveEvent(x, y, eventTime, null); 6278ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6288ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 6298ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onCancelEvent(x, y, eventTime); 6308ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6318ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 6328ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 6338ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 634f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public void onDownEvent(int x, int y, long eventTime, KeyEventHandler handler) { 635dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 636dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 6371d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 638f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 63963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 640f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyboardActionListener(handler.getKeyboardActionListener()); 641f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 642baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 6438a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 644160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka if (deltaT < sParams.mTouchNoiseThresholdTime) { 6458a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int dx = x - mLastX; 6468a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int dy = y - mLastY; 647baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka final int distanceSquared = (dx * dx + dy * dy); 6485c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (distanceSquared < sTouchNoiseThresholdDistanceSquared) { 649faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 650faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT 651faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka + " distance=" + distanceSquared); 6529bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 6539bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_onDownEvent(deltaT, distanceSquared); 6549bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 655d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 656baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 657baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 658baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 659baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 6605c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 661eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final Key key = getKeyOn(x, y); 6621d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 663e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null && key.isModifier()) { 6641d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 6651d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // tracked should be released. 6661d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.releaseAllPointers(eventTime); 6671d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 6681d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.add(this); 6691d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 6701d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 671eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (queue != null && queue.size() == 1) { 6729580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mIsPossibleGesture = false; 6739580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // A gesture should start only from the letter key. 6740657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka if (sShouldHandleGesture && mIsAlphabetKeyboard && !mIsShowingMoreKeysPanel 6750657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka && key != null && Keyboard.isLetterCode(key.mCode)) { 6769580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mIsPossibleGesture = true; 6770c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang // TODO: pointer times should be relative to first down even in entire batch input 6780c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang // instead of resetting to 0 for each new down event. 6799580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mGestureStroke.addPoint(x, y, 0, false); 6809580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 681eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 6821d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 6831d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 684baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onDownEventInternal(int x, int y, long eventTime) { 685e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onDownKey(x, y, eventTime); 68667a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 68732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. 688160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mIsAllowedSlidingKeyInput = sParams.mSlidingKeyInputEnabled 689c9f203805ca23276fcdcdc79b9298bc1d413ad98Tadashi G. Takaoka || (key != null && key.isModifier()) 69032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka || mKeyDetector.alwaysAllowsSlidingInput(); 6911a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 692c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka mKeyAlreadyProcessed = false; 693cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 694996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIgnoreModifierKey = false; 695e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 6961a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 697e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the new 6981a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 6992a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 700e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onDownKey(x, y, eventTime); 701e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 702996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 703e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 704e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 705e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setPressedKeyGraphics(key); 7066a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7076a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7086a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 709996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka private void startSlidingKeyInput(Key key) { 710e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (!mIsInSlidingKeyInput) { 711e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mIgnoreModifierKey = key.isModifier(); 712e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 713996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 714996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 715996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 7169580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka private void onGestureMoveEvent(PointerTracker tracker, int x, int y, long eventTime, 7179580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka boolean isHistorical, Key key) { 7189580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka final int gestureTime = (int)(eventTime - tracker.getDownTime()); 7190657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka if (sShouldHandleGesture && mIsPossibleGesture) { 7209580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka final GestureStroke stroke = mGestureStroke; 7219580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka stroke.addPoint(x, y, gestureTime, isHistorical); 7221e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka if (!mInGesture && stroke.isStartOfAGesture(gestureTime, sWasInGesture)) { 7239580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka startBatchInput(); 7249580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7259580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7269580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 7279580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (key != null && mInGesture) { 7289580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka final InputPointers batchPoints = getIncrementalBatchPoints(); 7294daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang mDrawingProxy.showGestureTrail(this); 7309580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) { 7319580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka updateBatchInput(batchPoints); 7329580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7339580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7349580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7359580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 7363314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka public void onMoveEvent(int x, int y, long eventTime, MotionEvent me) { 737dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_MOVE_EVENT) 738dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 739e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka if (mKeyAlreadyProcessed) 740e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 741baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 742eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (me != null) { 743eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Add historical points to gesture path. 744eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int pointerIndex = me.findPointerIndex(mPointerId); 745eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalSize = me.getHistorySize(); 746eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int h = 0; h < historicalSize; h++) { 747eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalX = (int)me.getHistoricalX(pointerIndex, h); 748eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalY = (int)me.getHistoricalY(pointerIndex, h); 749eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final long historicalTime = me.getHistoricalEventTime(h); 7509580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka onGestureMoveEvent(this, historicalX, historicalY, historicalTime, 751eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang true /* isHistorical */, null); 752eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 753eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 754eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 7558a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 7568a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 757e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key oldKey = mCurrentKey; 758e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onMoveKey(x, y); 759eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 760eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Register move event on gesture tracker. 7619580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka onGestureMoveEvent(this, x, y, eventTime, false /* isHistorical */, key); 7629580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (mInGesture) { 763eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mIgnoreModifierKey = true; 764eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mTimerProxy.cancelLongPressTimer(); 765eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mIsInSlidingKeyInput = true; 766eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mCurrentKey = null; 767eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang setReleasedKeyGraphics(oldKey); 768eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 769eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 770e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 771c0b5c9c43e5eb7a6ed768d56f462ca9ed5c5f913Tadashi G. Takaoka if (oldKey == null) { 7729e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 7739e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 7741a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 775e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the 7761a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // new keyboard layout. 7772a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 778e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onMoveKey(x, y); 779e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 780e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 781e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 782e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setPressedKeyGraphics(key); 783e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } else if (isMajorEnoughMoveToBeOnNewKey(x, y, key)) { 7849e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 7859e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 7869e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onPress() to notify that the new key is being pressed. 787e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 788e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 789996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 7902321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 791e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 79267a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 7931a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 794e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update key according 7951a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // to the new keyboard layout. 7962a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) { 797e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onMoveKey(x, y); 798e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 799e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 800e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 801e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setPressedKeyGraphics(key); 80267a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 803faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be translated to sudden 804faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move by touch panel firmware. This hack detects the case and translates the 805faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move event to successive up and down events. 806faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int dx = x - lastX; 807faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int dy = y - lastY; 808faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int lastMoveSquared = dx * dx + dy * dy; 809c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka // TODO: Should find a way to balance gesture detection and this hack. 810d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka if (sNeedsPhantomSuddenMoveEventHack 811c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka && lastMoveSquared >= mKeyQuarterWidthSquared 812c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka && !mIsPossibleGesture) { 813d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka if (DEBUG_MODE) { 814d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka Log.w(TAG, String.format("onMoveEvent:" 815d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka + " phantom sudden move event is translated to " 816faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); 817d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka } 818c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka // TODO: This should be moved to outside of this nested if-clause? 8199bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 8209bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); 8219bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 8220cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka onUpEventInternal(); 823faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 824faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } else { 8255e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // HACK: If there are currently multiple touches, register the key even if 8265e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // the finger slides off the key. This defends against noise from some 8275e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // touch panels when there are close multiple touches. 8285e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // Caveat: When in chording input mode with a modifier key, we don't use 8295e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka // this hack. 8305e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka if (me != null && me.getPointerCount() > 1 8315e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { 8320cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka onUpEventInternal(); 8335e06b8534ffdf5099d2ef4551b113a103cdf7061Tadashi G. Takaoka } 834c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka if (!mIsPossibleGesture) { 835c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka mKeyAlreadyProcessed = true; 836c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka } 837e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 838faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } 83967a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 840c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 8416a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 842e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, key)) { 8439e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 8449e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // notify that the previous key has been released. 845e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(oldKey); 846e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 847996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 84898b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 84967a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 850e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka onMoveToNewKey(key, x, y); 85167a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 852c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka if (!mIsPossibleGesture) { 853c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka mKeyAlreadyProcessed = true; 854c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka } 85567a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 85607221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 8576a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 8586a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 8596a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 860906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onUpEvent(int x, int y, long eventTime) { 861dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 862dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 8631d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 8645c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 8651d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 8669580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (!mInGesture) { 867eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (mCurrentKey != null && mCurrentKey.isModifier()) { 868eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Before processing an up event of modifier key, all pointers already being 869eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // tracked should be released. 870eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang queue.releaseAllPointersExcept(this, eventTime); 871eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } else { 872eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang queue.releaseAllPointersOlderThan(this, eventTime); 873eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 8741d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8751d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.remove(this); 8761d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8770cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka onUpEventInternal(); 8781d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8791d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 880d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 881d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 882d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 8830cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 8840cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka public void onPhantomUpEvent(long eventTime) { 885c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (DEBUG_EVENT) 8860cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka printTouchEvent("onPhntEvent:", getLastX(), getLastY(), eventTime); 8870cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka onUpEventInternal(); 888d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 8891d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 8901d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 8910cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka private void onUpEventInternal() { 8922321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 893cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 894c902dfeb8f8b889e885565a000556419e0d8307fTadashi G. Takaoka mIsPossibleGesture = false; 8955a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka // Release the last pressed key. 8965a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 8979d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 8989d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 8999d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 9009ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 901eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 9029580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (mInGesture) { 903eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Register up event on gesture tracker. 9049580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // TODO: Figure out how to deal with multiple fingers that are in gesture, sliding, 9059580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka // and/or tapping mode? 9069580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka endBatchInput(getAllBatchPoints()); 907eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (mCurrentKey != null) { 908eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang callListenerOnRelease(mCurrentKey, mCurrentKey.mCode, true); 9099580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka mCurrentKey = null; 910eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 9114daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang mDrawingProxy.showGestureTrail(this); 912eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 913eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 9140c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang // This event will be recognized as a regular code input. Clear unused batch points so they 9150c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang // are not mistakenly included in the next batch event. 9160c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang clearBatchInputPointsOfAllPointerTrackers(); 917d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka if (mKeyAlreadyProcessed) 918d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 9190d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka if (mCurrentKey != null && !mCurrentKey.isRepeatable()) { 9205a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka detectAndSendKey(mCurrentKey, mKeyX, mKeyY); 9216a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9226a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9236a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 924e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaoka public void onShowMoreKeysPanel(int x, int y, KeyEventHandler handler) { 9251e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka abortBatchInput(); 9269ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka onLongPressed(); 9279d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = true; 928cc3500b0c8f11e8de1ad7376dda466d30637e462Tadashi G. Takaoka onDownEvent(x, y, SystemClock.uptimeMillis(), handler); 9299ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 9309ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 931906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 932d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 933e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 9345c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 9351ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka if (queue != null) { 936d00d963b9d47c1bba6f65534033a33fe7c30dde5Tadashi G. Takaoka queue.remove(this); 9371ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka } 938d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 939d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 940906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onCancelEvent(int x, int y, long eventTime) { 941dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 942dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 9431d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 9445c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 945c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (queue != null) { 946d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka queue.releaseAllPointersExcept(this, eventTime); 9471d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.remove(this); 948c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 949baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 9501d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9511d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 952baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 9532321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 954e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey); 955cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 9569d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 9579d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 9589d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 9599ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 9606a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9616a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 962e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private void startRepeatKey(Key key) { 9639580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (key != null && key.isRepeatable() && !mInGesture) { 9646662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv onRegisterKey(key); 965a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(this); 966a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 967a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 968a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 9696662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv public void onRegisterKey(Key key) { 970c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka if (key != null) { 971e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka detectAndSendKey(key, key.mX, key.mY); 972d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka mTimerProxy.startTypingStateTimer(key); 973c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 9746a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9756a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 976e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, Key newKey) { 977b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka if (mKeyDetector == null) 978a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 979e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key curKey = mCurrentKey; 9806a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 981e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 982e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } else if (curKey != null) { 983e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return curKey.squaredDistanceToEdge(x, y) 984a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka >= mKeyDetector.getKeyHysteresisDistanceSquared(); 9856a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 986e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 9876a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9886a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9896a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 990e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private void startLongPressTimer(Key key) { 9919580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka if (key != null && key.isLongPressEnabled() && !mInGesture) { 992a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mTimerProxy.startLongPressTimer(this); 9934189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 99466e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 99566e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 996e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private void detectAndSendKey(Key key, int x, int y) { 99783e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 9988aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 999dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 1000dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 100166e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 10022013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka int code = key.mCode; 1003ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok callListenerOnCodeInput(key, code, x, y); 10042013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka callListenerOnRelease(key, code, false); 10051e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka sWasInGesture = false; 10066a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10076a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1008dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private void printTouchEvent(String title, int x, int y, long eventTime) { 1009723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka final Key key = mKeyDetector.detectHitKey(x, y); 1010e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka final String code = KeyDetector.printableCode(key); 1011e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title, 1012d7edd1cbb5dfacacdd39766e379fb60d2b7c6b73Tadashi G. Takaoka (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, eventTime, code)); 1013dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 10146e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 1015