16a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka/* 28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 36a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License. 68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at 76a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 96a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 106a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and 148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License. 156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka */ 166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 19536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaokaimport android.content.res.Resources; 205509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport android.content.res.TypedArray; 21e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaokaimport android.os.SystemClock; 22c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport android.util.Log; 238ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaokaimport android.view.MotionEvent; 24c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 254a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.BatchInputArbiter; 264a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.BatchInputArbiter.BatchInputArbiterListener; 27c986d16e8aa97c042e1791cabb0a79bb9aaf04a1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.BogusMoveEventDetector; 2834a9e2ae87c6718d439b294d9536b6587a4f89f8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.DrawingProxy; 29a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureEnabler; 30e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeDrawingParams; 31e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeDrawingPoints; 32e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureStrokeRecognitionParams; 3372934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 3434a9e2ae87c6718d439b294d9536b6587a4f89f8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.TimerProxy; 355045103d6174a059bceb5ab9c7c03ef48e263c95Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.TypingTimeRecorder; 365509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaokaimport com.android.inputmethod.latin.R; 379342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants; 385b91b551e5ffaf2c2e691dfbd434f21c82293986Jean Chalardimport com.android.inputmethod.latin.common.CoordinateUtils; 3936799b2aa2982ec17341cd2c5ed81e608bcee8c6Jean Chalardimport com.android.inputmethod.latin.common.InputPointers; 402dae79b1966a7970c25c8b79beec1c95c13f6c87Tadashi G. Takaokaimport com.android.inputmethod.latin.define.DebugFlags; 41212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaokaimport com.android.inputmethod.latin.settings.Settings; 42536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaokaimport com.android.inputmethod.latin.utils.ResourceUtils; 436a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 445c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 45dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 46051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaokaimport javax.annotation.Nonnull; 47051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaokaimport javax.annotation.Nullable; 48051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka 494a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaokapublic final class PointerTracker implements PointerTrackerQueue.Element, 504a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka BatchInputArbiterListener { 51dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 52dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 53dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 54dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 552dae79b1966a7970c25c8b79beec1c95c13f6c87Tadashi G. Takaoka private static boolean DEBUG_MODE = DebugFlags.DEBUG_ENABLED || DEBUG_EVENT; 5640a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 57a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka static final class PointerTrackerParams { 582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public final boolean mKeySelectionByDraggingFinger; 595509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public final int mTouchNoiseThresholdTime; 60b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka public final int mTouchNoiseThresholdDistance; 613623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka public final int mSuppressKeyPreviewAfterBatchInputDuration; 628126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka public final int mKeyRepeatStartTimeout; 638126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka public final int mKeyRepeatInterval; 64212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public final int mLongPressShiftLockTimeout; 655509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 6680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) { 672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeySelectionByDraggingFinger = mainKeyboardViewAttr.getBoolean( 682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_keySelectionByDraggingFinger, false); 695509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( 705509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); 71b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( 725509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); 733623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt( 743623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0); 758126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt( 768126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0); 778126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka mKeyRepeatInterval = mainKeyboardViewAttr.getInt( 788126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatInterval, 0); 79212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mLongPressShiftLockTimeout = mainKeyboardViewAttr.getInt( 80212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka R.styleable.MainKeyboardView_longPressShiftLockTimeout, 0); 815509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 825509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka } 835509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 84a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka private static GestureEnabler sGestureEnabler = new GestureEnabler(); 85a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka 86160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka // Parameters for pointer handling. 875509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private static PointerTrackerParams sParams; 88e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka private static GestureStrokeRecognitionParams sGestureStrokeRecognitionParams; 89e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka private static GestureStrokeDrawingParams sGestureStrokeDrawingParams; 90d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka private static boolean sNeedsPhantomSuddenMoveEventHack; 91b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // Move this threshold to resource. 92b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka // TODO: Device specific parameter would be better for device specific hack? 93b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth 945c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 95a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka private static final ArrayList<PointerTracker> sTrackers = new ArrayList<>(); 9693b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue(); 975c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 985c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 996a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static DrawingProxy sDrawingProxy; 1012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static TimerProxy sTimerProxy; 1022fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static KeyboardActionListener sListener = KeyboardActionListener.EMPTY_LISTENER; 103baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 104921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka // The {@link KeyDetector} is set whenever the down event is processed. Also this is updated 105921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka // when new {@link Keyboard} is set by {@link #setKeyDetector(KeyDetector)}. 106ef8a03685f46c7a3ce02ad4a568217c9ef7fe677Tadashi G. Takaoka private KeyDetector mKeyDetector = new KeyDetector(); 1075a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 1082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private int mPhantomSuddenMoveThreshold; 109b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); 1106a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1116c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private boolean mIsDetectingGesture = false; // per PointerTracker. 1126c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private static boolean sInGesture = false; 1135045103d6174a059bceb5ab9c7c03ef48e263c95Tadashi G. Takaoka private static TypingTimeRecorder sTypingTimeRecorder; 1149580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 1158a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 1168a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 117be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka @Nonnull 118547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka private int[] mDownCoordinates = CoordinateUtils.newInstance(); 1198a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 1208a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 121e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The current key where this pointer is. 122e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mCurrentKey = null; 123e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // The position where the current key was recognized for the first time. 1248a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 1258a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 1268a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 1278a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 1288a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 1298a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 1306a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1311a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 1321a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 1331a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 13413d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // true if this pointer is no longer triggering any action because it has been canceled. 13513d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka private boolean mIsTrackingForActionDisabled; 136c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 13735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang // the more keys panel currently being shown. equals null if no panel is active. 13835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private MoreKeysPanel mMoreKeysPanel; 1399ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 140212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka private static final int MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT = 3; 1412fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // true if this pointer is in the dragging finger mode. 1422fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa boolean mIsInDraggingFinger; 1432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // true if this pointer is sliding from a modifier key and in the sliding key input mode, 144f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // so that further modifier keys should be ignored. 1452fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa boolean mIsInSlidingKeyInput; 146a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka // if not a NOT_A_CODE, the key of this code is repeating 147a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka private int mCurrentRepeatingKeyCode = Constants.NOT_A_CODE; 148cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 1492fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // true if dragging finger is allowed. 1502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private boolean mIsAllowedDraggingFinger; 15167a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 1524a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka private final BatchInputArbiter mBatchInputArbiter; 153e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka private final GestureStrokeDrawingPoints mGestureStrokeDrawingPoints; 154f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 1552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Add PointerTrackerFactory singleton and move some class static methods into it. 1562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public static void init(final TypedArray mainKeyboardViewAttr, final TimerProxy timerProxy, 157921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka final DrawingProxy drawingProxy) { 1582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sParams = new PointerTrackerParams(mainKeyboardViewAttr); 159e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka sGestureStrokeRecognitionParams = new GestureStrokeRecognitionParams(mainKeyboardViewAttr); 160e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka sGestureStrokeDrawingParams = new GestureStrokeDrawingParams(mainKeyboardViewAttr); 1615045103d6174a059bceb5ab9c7c03ef48e263c95Tadashi G. Takaoka sTypingTimeRecorder = new TypingTimeRecorder( 162e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka sGestureStrokeRecognitionParams.mStaticTimeThresholdAfterFastTyping, 1635045103d6174a059bceb5ab9c7c03ef48e263c95Tadashi G. Takaoka sParams.mSuppressKeyPreviewAfterBatchInputDuration); 1642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 1652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final Resources res = mainKeyboardViewAttr.getResources(); 166536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka sNeedsPhantomSuddenMoveEventHack = Boolean.parseBoolean( 167bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka ResourceUtils.getDeviceOverrideValue(res, 168bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka R.array.phantom_sudden_move_event_device_list, Boolean.FALSE.toString())); 169c986d16e8aa97c042e1791cabb0a79bb9aaf04a1Tadashi G. Takaoka BogusMoveEventDetector.init(res); 17093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 1712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sTimerProxy = timerProxy; 1722fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sDrawingProxy = drawingProxy; 1736a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1746a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1758335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 176694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 177a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka sGestureEnabler.setMainDictionaryAvailability(mainDictionaryAvailable); 1788335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 1798335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 180694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 181a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka sGestureEnabler.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser); 182918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka } 183918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka 1842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public static PointerTracker getPointerTracker(final int id) { 185b4fbbe57f574ce6e6a5827156f875fe7d3eb5089Tadashi G. Takaoka final ArrayList<PointerTracker> trackers = sTrackers; 1865c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1875c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 1885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 1892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final PointerTracker tracker = new PointerTracker(i); 1905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 1915c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1925c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1935c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 1945c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public static boolean isAnyInDraggingFinger() { 1972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return sPointerTrackerQueue.isAnyInDraggingFinger(); 1985c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1995c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2005c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka public static void cancelAllPointerTrackers() { 2015c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka sPointerTrackerQueue.cancelAllPointerTrackers(); 2025c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka } 2035c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka 204694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyboardActionListener(final KeyboardActionListener listener) { 2052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sListener = listener; 2065c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2075c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 208694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public static void setKeyDetector(final KeyDetector keyDetector) { 2099fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 2109fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka if (keyboard == null) { 2119fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka return; 2129fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka } 213afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 214afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 215afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 2165c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 2175c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 218a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka sGestureEnabler.setPasswordMode(keyboard.mId.passwordInput()); 2195c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2205c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 221dde36ef34329164cf8b8a3985c578dab0343b3ebTadashi G. Takaoka public static void setReleasedKeyGraphicsToAllKeys() { 222afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final int trackersSize = sTrackers.size(); 223afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa for (int i = 0; i < trackersSize; ++i) { 224afed0567e91b9411fa61b03f5ac17812db56fd18Ken Wakasa final PointerTracker tracker = sTrackers.get(i); 22553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.getKey(), true /* withAnimation */); 2265c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2275c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2285c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 229ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang public static void dismissAllMoreKeysPanels() { 230ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final int trackersSize = sTrackers.size(); 231ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang for (int i = 0; i < trackersSize; ++i) { 232ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang final PointerTracker tracker = sTrackers.get(i); 2332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa tracker.dismissMoreKeysPanel(); 234ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 235ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 236ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 2372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private PointerTracker(final int id) { 2385c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 2394a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mBatchInputArbiter = new BatchInputArbiter(id, sGestureStrokeRecognitionParams); 240c3fe1425a5941e4801caa681dd53fb742d4489d9Tadashi G. Takaoka mGestureStrokeDrawingPoints = new GestureStrokeDrawingPoints(sGestureStrokeDrawingParams); 2416a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 2426a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 2431a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 2448126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key, 245ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka final int repeatCount) { 24613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // While gesture input is going on, this method should be a no-operation. But when gesture 24713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // input has been canceled, <code>sInGesture</code> and <code>mIsDetectingGesture</code> 24813d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // are set to false. To keep this method is a no-operation, 24913d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // <code>mIsTrackingForActionDisabled</code> should also be taken account of. 25013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (sInGesture || mIsDetectingGesture || mIsTrackingForActionDisabled) { 251eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return false; 252eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 2532fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final boolean ignoreModifierKey = mIsInDraggingFinger && key.isModifier(); 254e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 2558126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onPress : %s%s%s%s", mPointerId, 2569fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka (key == null ? "none" : Constants.printableCode(key.getCode())), 25758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka ignoreModifierKey ? " ignoreModifier" : "", 2588126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka key.isEnabled() ? "" : " disabled", 259ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka repeatCount > 0 ? " repeatCount=" + repeatCount : "")); 260e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 26193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (ignoreModifierKey) { 262996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 26393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 264e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 2652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sListener.onPressKey(key.getCode(), repeatCount, getActivePointerTrackerCount() == 1); 266690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 267690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 2682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sTimerProxy.startTypingStateTimer(key); 269690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 270690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 271690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 272dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 273dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 274690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 27529881854bc5a625d01bad8c678ac10e6d1877e5fJean Chalard // primaryCode is different from {@link Key#mKeyCode}. 276694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, 2772282e8520a2c1984989a14fb09896536f5033b26Jean Chalard final int y, final long eventTime, final boolean isKeyRepeat) { 2782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final boolean ignoreModifierKey = mIsInDraggingFinger && key.isModifier(); 2792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final boolean altersCode = key.altCodeWhileTyping() && sTimerProxy.isTypingState(); 28029d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int code = altersCode ? key.getAltCode() : primaryCode; 2812013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (DEBUG_LISTENER) { 282240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final String output = code == Constants.CODE_OUTPUT_TEXT 283240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka ? key.getOutputText() : Constants.printableCode(code); 28458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCodeInput: %4d %4d %s%s%s", mPointerId, x, y, 28558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka output, ignoreModifierKey ? " ignoreModifier" : "", 28658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka altersCode ? " altersCode" : "", key.isEnabled() ? "" : " disabled")); 2872013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 288e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 289996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 290e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 2916bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 2926bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.isEnabled() || altersCode) { 2935045103d6174a059bceb5ab9c7c03ef48e263c95Tadashi G. Takaoka sTypingTimeRecorder.onCodeInput(code, eventTime); 294240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (code == Constants.CODE_OUTPUT_TEXT) { 2952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sListener.onTextInput(key.getOutputText()); 296240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (code != Constants.CODE_UNSPECIFIED) { 297a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard if (mKeyboard.hasProximityCharsCorrection(code)) { 2982282e8520a2c1984989a14fb09896536f5033b26Jean Chalard sListener.onCodeInput(code, x, y, isKeyRepeat); 299a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard } else { 300a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard sListener.onCodeInput(code, 3012282e8520a2c1984989a14fb09896536f5033b26Jean Chalard Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, isKeyRepeat); 302a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard } 3032013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 30493246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 305dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 306dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 307f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may be in shifted state and the 30829881854bc5a625d01bad8c678ac10e6d1877e5fJean Chalard // primaryCode is different from {@link Key#mKeyCode}. 309694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void callListenerOnRelease(final Key key, final int primaryCode, 310694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final boolean withSliding) { 31113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka // See the comment at {@link #callListenerOnPressAndCheckKeyboardLayoutChange(Key}}. 31213d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (sInGesture || mIsDetectingGesture || mIsTrackingForActionDisabled) { 313eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 314eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 3152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final boolean ignoreModifierKey = mIsInDraggingFinger && key.isModifier(); 316e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka if (DEBUG_LISTENER) { 31758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, 318240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka Constants.printableCode(primaryCode), 31958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka withSliding ? " sliding" : "", ignoreModifierKey ? " ignoreModifier" : "", 32058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka key.isEnabled() ? "": " disabled")); 321e742436a29f46764441e83aaebf3ec25283bff1bTadashi G. Takaoka } 322e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (ignoreModifierKey) { 323996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 324e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 32593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka if (key.isEnabled()) { 3262fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sListener.onReleaseKey(primaryCode, withSliding); 32793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 328dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 329dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 33041016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka private void callListenerOnFinishSlidingInput() { 33141016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka if (DEBUG_LISTENER) { 33241016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onFinishSlidingInput", mPointerId)); 33341016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 3342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sListener.onFinishSlidingInput(); 33541016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 33641016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka 3378aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 338694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_LISTENER) { 33958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelInput", mPointerId)); 340694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 3412fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sListener.onCancelInput(); 342dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 343dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 344694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void setKeyDetectorInner(final KeyDetector keyDetector) { 34558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final Keyboard keyboard = keyDetector.getKeyboard(); 3469fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka if (keyboard == null) { 3479fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka return; 3489fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka } 34958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (keyDetector == mKeyDetector && keyboard == mKeyboard) { 35058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return; 35158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 352a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 3539fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka mKeyboard = keyboard; 3542fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Mark that keyboard layout has been changed. 3552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyboardLayoutHasBeenChanged = true; 356d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyWidth = mKeyboard.mMostCommonKeyWidth; 357d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka final int keyHeight = mKeyboard.mMostCommonKeyHeight; 3584a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mBatchInputArbiter.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); 359075158ccd039e4cc7e78d9db0470500e60c3fa1bTadashi G. Takaoka // Keep {@link #mCurrentKey} that comes from previous keyboard. The key preview of 360075158ccd039e4cc7e78d9db0470500e60c3fa1bTadashi G. Takaoka // {@link #mCurrentKey} will be dismissed by {@setReleasedKeyGraphics(Key)} via 361075158ccd039e4cc7e78d9db0470500e60c3fa1bTadashi G. Takaoka // {@link onMoveEventInternal(int,int,long)} or {@link #onUpEventInternal(int,int,long)}. 3622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mPhantomSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); 363d631778e1c1ffcdf28129894239e7ee7d6f399fcTadashi G. Takaoka mBogusMoveEventDetector.setKeyboardGeometry(keyWidth, keyHeight); 3645a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 3655a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 3660cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 3672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public boolean isInDraggingFinger() { 3682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return mIsInDraggingFinger; 369cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 370cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 371051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka @Nullable 372e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka public Key getKey() { 373e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey; 374dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 375dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 3760cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 3772aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 378e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return mCurrentKey != null && mCurrentKey.isModifier(); 3792aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 3802aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 381694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public Key getKeyOn(final int x, final int y) { 382723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 3832aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 3842aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 38553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka private void setReleasedKeyGraphics(@Nullable final Key key, final boolean withAnimation) { 3866bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 387faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 388faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 389faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 39053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sDrawingProxy.onKeyReleased(key, withAnimation); 391faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 392faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 393faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 394faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 39553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sDrawingProxy.onKeyReleased(shiftKey, false /* withAnimation */); 3962013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 3972013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 398faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 3992013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 400faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.altCodeWhileTyping()) { 40129d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 402faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 403faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 40453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sDrawingProxy.onKeyReleased(altKey, false /* withAnimation */); 405faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 406faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 40729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 40853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sDrawingProxy.onKeyReleased(k, false /* withAnimation */); 4092013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4102013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4116a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4126a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4136a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 41429d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) { 415a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka if (!sGestureEnabler.shouldHandleGesture()) return false; 4165045103d6174a059bceb5ab9c7c03ef48e263c95Tadashi G. Takaoka return sTypingTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime); 41729d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka } 41829d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka 41953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka private void setPressedKeyGraphics(@Nullable final Key key, final long eventTime) { 4206bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key == null) { 4216bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka return; 4226bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 4236bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka 4246bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. 4252fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final boolean altersCode = key.altCodeWhileTyping() && sTimerProxy.isTypingState(); 4266bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; 4276bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (!needsToUpdateGraphics) { 428faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka return; 429faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 430faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 43153b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka final boolean noKeyPreview = sInGesture || needsToSuppressKeyPreviewPopup(eventTime); 43253b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sDrawingProxy.onKeyPressed(key, !noKeyPreview); 433faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka 434faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (key.isShift()) { 435faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key shiftKey : mKeyboard.mShiftKeys) { 436faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (shiftKey != key) { 43753b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sDrawingProxy.onKeyPressed(shiftKey, false /* withPreview */); 4382013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4392013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 440faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 4412013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 442aa7a68a3e0211a9e6c6da20c0f76aace3b3ba011Tadashi G. Takaoka if (altersCode) { 44329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int altCode = key.getAltCode(); 444faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka final Key altKey = mKeyboard.getKey(altCode); 445faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka if (altKey != null) { 44653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sDrawingProxy.onKeyPressed(altKey, false /* withPreview */); 447faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka } 448faad353feabef17e3bea6d5d9b4cb8bacf94788cTadashi G. Takaoka for (final Key k : mKeyboard.mAltCodeKeysWhileTyping) { 44929d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka if (k != key && k.getAltCode() == altCode) { 45053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sDrawingProxy.onKeyPressed(k, false /* withPreview */); 4512013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 4522013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 453d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 454c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 455c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 456e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka public GestureStrokeDrawingPoints getGestureStrokeDrawingPoints() { 457e2a6253cb581f9ab70cfb723d32b14f9ac7d2ab7Tadashi G. Takaoka return mGestureStrokeDrawingPoints; 4582f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang } 4592f81757c3a5eb50d41ce19fb534f72cbf607a997Tom Ouyang 460be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka public void getLastCoordinates(@Nonnull final int[] outCoords) { 461547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.set(outCoords, mLastX, mLastY); 4628a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 4638a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 4648a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 4658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 4668a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 4678a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 468be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka public void getDownCoordinates(@Nonnull final int[] outCoords) { 469547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.copy(outCoords, mDownCoordinates); 470547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka } 471547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka 472694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onDownKey(final int x, final int y, final long eventTime) { 4738a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 474547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.set(mDownCoordinates, x, y); 475b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onDownKey(); 4768a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 4778a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 4788a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 479c986d16e8aa97c042e1791cabb0a79bb9aaf04a1Tadashi G. Takaoka private static int getDistance(final int x1, final int y1, final int x2, final int y2) { 480b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka return (int)Math.hypot(x1 - x2, y1 - y2); 481b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 482b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka 483694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKeyInternal(final int x, final int y) { 484b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onMoveKey(getDistance(x, y, mLastX, mLastY)); 4858a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 4868a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 487723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka return mKeyDetector.detectHitKey(x, y); 4888a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 4898a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 490694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveKey(final int x, final int y) { 4918a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 4928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 4938a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 494694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private Key onMoveToNewKey(final Key newKey, final int x, final int y) { 495e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mCurrentKey = newKey; 4968a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 4978a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 498e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka return newKey; 4998a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 5008a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 5012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa /* package */ static int getActivePointerTrackerCount() { 50293b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka return sPointerTrackerQueue.size(); 5036c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 5046c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 505212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka private boolean isOldestTrackerInQueue() { 506ab334eb64669e909f0a401fddffa891962002602Tadashi G. Takaoka return sPointerTrackerQueue.getOldestElement() == this; 50713ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka } 50813ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka 5094a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka // Implements {@link BatchInputArbiterListener}. 5104a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka @Override 5114a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void onStartBatchInput() { 5129c5d165e9c5797f16d3b07b043a5525353ad0d4fTadashi G. Takaoka if (DEBUG_LISTENER) { 51358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); 5149580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5154a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sListener.onStartBatchInput(); 5164a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka dismissAllMoreKeysPanels(); 51734a9e2ae87c6718d439b294d9536b6587a4f89f8Tadashi G. Takaoka sTimerProxy.cancelLongPressTimersOf(this); 51872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 51972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 520904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka private void showGestureTrail() { 52113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 5226f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka return; 5236f0a60d10de056cbb89cf7984c9f8f64bb95db9dTadashi G. Takaoka } 524212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka // A gesture floating preview text will be shown at the oldest pointer/finger on the screen. 5252fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sDrawingProxy.showGestureTrail( 526212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka this, isOldestTrackerInQueue() /* showsFloatingPreviewText */); 52772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 52872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 529904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka public void updateBatchInputByTimer(final long syntheticMoveEventTime) { 5304a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mBatchInputArbiter.updateBatchInputByTimer(syntheticMoveEventTime, this); 5314a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 5324a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 5334a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka // Implements {@link BatchInputArbiterListener}. 5344a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka @Override 5354a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void onUpdateBatchInput(final InputPointers aggregatedPointers, final long eventTime) { 5364a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (DEBUG_LISTENER) { 5374a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, 5384a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka aggregatedPointers.getPointerSize())); 5399580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5404a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sListener.onUpdateBatchInput(aggregatedPointers); 5419580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5429580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 5434a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka // Implements {@link BatchInputArbiterListener}. 5444a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka @Override 5454a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void onStartUpdateBatchInputTimer() { 5464a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sTimerProxy.startUpdateBatchInputTimer(this); 5474a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 5484a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka 5494a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka // Implements {@link BatchInputArbiterListener}. 5504a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka @Override 5514a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka public void onEndBatchInput(final InputPointers aggregatedPointers, final long eventTime) { 5524a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sTypingTimeRecorder.onEndBatchInput(eventTime); 5534a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sTimerProxy.cancelAllUpdateBatchInputTimers(); 5544a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 5554a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka return; 5564a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka } 5574a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (DEBUG_LISTENER) { 5584a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", 5594a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mPointerId, aggregatedPointers.getPointerSize())); 5609580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5614a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sListener.onEndBatchInput(aggregatedPointers); 5629580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 5639580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 5648e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka private void cancelBatchInput() { 5655c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka cancelAllPointerTrackers(); 5668353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka mIsDetectingGesture = false; 5677c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka if (!sInGesture) { 5687c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka return; 5697c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka } 5708e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sInGesture = false; 5718e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka if (DEBUG_LISTENER) { 5728e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onCancelBatchInput", mPointerId)); 5738e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } 5742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sListener.onCancelBatchInput(); 5758e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } 5768e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka 5772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void processMotionEvent(final MotionEvent me, final KeyDetector keyDetector) { 578e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int action = me.getActionMasked(); 579e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final long eventTime = me.getEventTime(); 580e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka if (action == MotionEvent.ACTION_MOVE) { 5812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // When this pointer is the only active pointer and is showing a more keys panel, 5822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // we should ignore other pointers' motion event. 5832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final boolean shouldIgnoreOtherPointers = 5842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa isShowingMoreKeysPanel() && getActivePointerTrackerCount() == 1; 585e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int pointerCount = me.getPointerCount(); 586e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka for (int index = 0; index < pointerCount; index++) { 587e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int id = me.getPointerId(index); 5882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (shouldIgnoreOtherPointers && id != mPointerId) { 5892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa continue; 5902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 591e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int x = (int)me.getX(index); 592e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int y = (int)me.getY(index); 5932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final PointerTracker tracker = getPointerTracker(id); 594e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka tracker.onMoveEvent(x, y, eventTime, me); 595e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka } 596e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka return; 597e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka } 598e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int index = me.getActionIndex(); 599e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int x = (int)me.getX(index); 600e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int y = (int)me.getY(index); 6018ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka switch (action) { 6028ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 6038ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 6042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa onDownEvent(x, y, eventTime, keyDetector); 6058ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6068ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_UP: 6078ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 6088ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onUpEvent(x, y, eventTime); 6098ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6108ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 6118ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka onCancelEvent(x, y, eventTime); 6128ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka break; 6138ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 6148ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka } 6158ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 616e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka private void onDownEvent(final int x, final int y, final long eventTime, 6172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final KeyDetector keyDetector) { 6187a750ca50d0ebe6bb5f395479ae2bef355c0a5ddTadashi G. Takaoka setKeyDetectorInner(keyDetector); 619694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 620dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 621694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 622baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 6238a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 624160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka if (deltaT < sParams.mTouchNoiseThresholdTime) { 625b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final int distance = getDistance(x, y, mLastX, mLastY); 626b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka if (distance < sParams.mTouchNoiseThresholdDistance) { 627faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 628b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onDownEvent:" 629b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka + " ignore potential noise: time=%d distance=%d", 630b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mPointerId, deltaT, distance)); 63113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 632baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 633baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 634baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 635baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 636eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final Key key = getKeyOn(x, y); 637b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka mBogusMoveEventDetector.onActualDownEvent(x, y); 63893b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (key != null && key.isModifier()) { 63993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 64093b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 64193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 6421d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 64393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.add(this); 6441d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 645a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka if (!sGestureEnabler.shouldHandleGesture()) { 6466c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 6476c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 6480938fb6913c10d32f0a870210fc208c7bbfe282cSatoshi Kataoka // A gesture should start only from a non-modifier key. Note that the gesture detection is 6490938fb6913c10d32f0a870210fc208c7bbfe282cSatoshi Kataoka // disabled when the key is repeating. 650b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() 6510938fb6913c10d32f0a870210fc208c7bbfe282cSatoshi Kataoka && key != null && !key.isModifier(); 652b305e6775a214f1cc16e584484e26a47eb8baa52Tadashi G. Takaoka if (mIsDetectingGesture) { 6534a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mBatchInputArbiter.addDownEventPoint(x, y, eventTime, 6544a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka sTypingTimeRecorder.getLastLetterTypingTime(), getActivePointerTrackerCount()); 6554a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mGestureStrokeDrawingPoints.onDownEvent( 6564a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka x, y, mBatchInputArbiter.getElapsedTimeSinceFirstDown(eventTime)); 657eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 6581d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 6591d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 6602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa /* package */ boolean isShowingMoreKeysPanel() { 66135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return (mMoreKeysPanel != null); 66235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 66335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 6642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private void dismissMoreKeysPanel() { 6652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (isShowingMoreKeysPanel()) { 6662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mMoreKeysPanel.dismissMoreKeysPanel(); 6672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mMoreKeysPanel = null; 6682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 671694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void onDownEventInternal(final int x, final int y, final long eventTime) { 672e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka Key key = onDownKey(x, y, eventTime); 6732fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Key selection by dragging finger is allowed when 1) key selection by dragging finger is 6742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // enabled by configuration, 2) this pointer starts dragging from modifier key, or 3) this 6752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // pointer's KeyDetector always allows key selection by dragging finger, such as 6762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // {@link MoreKeysKeyboard}. 6772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mIsAllowedDraggingFinger = sParams.mKeySelectionByDraggingFinger 678c9f203805ca23276fcdcdc79b9298bc1d413ad98Tadashi G. Takaoka || (key != null && key.isModifier()) 6792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa || mKeyDetector.alwaysAllowsKeySelectionByDraggingFinger(); 6801a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 68113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka mIsTrackingForActionDisabled = false; 6822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa resetKeySelectionByDraggingFinger(); 683e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (key != null) { 6841a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 685e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update key according to the new 6861a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 687ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) { 688e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka key = onDownKey(x, y, eventTime); 689e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 690996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 691e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startRepeatKey(key); 692e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka startLongPressTimer(key); 69329d2d4818266e76930b9f5376b1a7ebacd0c9f25Tadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 6946a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6956a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6966a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 6972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private void startKeySelectionByDraggingFinger(final Key key) { 6982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (!mIsInDraggingFinger) { 6992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mIsInSlidingKeyInput = key.isModifier(); 700e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka } 7012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mIsInDraggingFinger = true; 702996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 703996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 7042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private void resetKeySelectionByDraggingFinger() { 7052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mIsInDraggingFinger = false; 706f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mIsInSlidingKeyInput = false; 707051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka sDrawingProxy.showSlidingKeyInputPreview(null /* tracker */); 708f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka } 709f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka 7106c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onGestureMoveEvent(final int x, final int y, final long eventTime, 71102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final boolean isMajorEvent, final Key key) { 712904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka if (!mIsDetectingGesture) { 713904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka return; 714904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka } 7154a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka final boolean onValidArea = mBatchInputArbiter.addMoveEventPoint( 7164a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka x, y, eventTime, isMajorEvent, this); 717904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka // If the move event goes out from valid batch input area, cancel batch input. 718904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka if (!onValidArea) { 719904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka cancelBatchInput(); 720904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka return; 721904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka } 7224a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mGestureStrokeDrawingPoints.onMoveEvent( 7234a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka x, y, mBatchInputArbiter.getElapsedTimeSinceFirstDown(eventTime)); 724904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka // If the MoreKeysPanel is showing then do not attempt to enter gesture mode. However, 725904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka // the gestured touch points are still being recorded in case the panel is dismissed. 726904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 727904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka return; 728904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka } 729904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka if (!sInGesture && key != null && Character.isLetter(key.getCode()) 7304a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka && mBatchInputArbiter.mayStartBatchInput(this)) { 731904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka sInGesture = true; 732904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka } 733904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka if (sInGesture) { 734904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka if (key != null) { 7354a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka mBatchInputArbiter.updateBatchInput(eventTime, this); 7369580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 737904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka showGestureTrail(); 7389580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7399580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka } 7409580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka 741e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka private void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) { 742694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_MOVE_EVENT) { 743dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 744694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 74513d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 746e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 747694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 748baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 749a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka if (sGestureEnabler.shouldHandleGesture() && me != null) { 750eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // Add historical points to gesture path. 751eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int pointerIndex = me.findPointerIndex(mPointerId); 752eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalSize = me.getHistorySize(); 753eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int h = 0; h < historicalSize; h++) { 754eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalX = (int)me.getHistoricalX(pointerIndex, h); 755eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int historicalY = (int)me.getHistoricalY(pointerIndex, h); 756eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final long historicalTime = me.getHistoricalEventTime(h); 7576c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onGestureMoveEvent(historicalX, historicalY, historicalTime, 75802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka false /* isMajorEvent */, null); 759eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 760eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 761ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 762ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang if (isShowingMoreKeysPanel()) { 763ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka final int translatedX = mMoreKeysPanel.translateX(x); 764ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka final int translatedY = mMoreKeysPanel.translateY(y); 765ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime); 766ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka onMoveKey(x, y); 7672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (mIsInSlidingKeyInput) { 7682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sDrawingProxy.showSlidingKeyInputPreview(this); 769212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 770ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang return; 771ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 7726c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka onMoveEventInternal(x, y, eventTime); 7736c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 7746c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka 7752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private void processDraggingFingerInToNewKey(final Key newKey, final int x, final int y, 7763c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime) { 7773c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 7783c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update key according 7793c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka // to the new keyboard layout. 7803c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Key key = newKey; 781ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) { 7823c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka key = onMoveKey(x, y); 7833c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 7843c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onMoveToNewKey(key, x, y); 78513d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 78613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka return; 78713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka } 7883c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka startLongPressTimer(key); 7893c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka setPressedKeyGraphics(key, eventTime); 7903c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 7913c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 7923c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processPhantomSuddenMoveHack(final Key key, final int x, final int y, 7933c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 7943c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 7953c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 7963c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " phantom sudden move event (distance=%d) is translated to " 7973c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + "up[%d,%d,%s]/down[%d,%d,%s] events", mPointerId, 7983c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka getDistance(x, y, lastX, lastY), 7997dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.getCode()), 8007dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka x, y, Constants.printableCode(key.getCode()))); 8013c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 80235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 8033c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 8043c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 8053c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 8063c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka private void processProximateBogusDownMoveUpEventHack(final Key key, final int x, final int y, 8073c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 8083c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (DEBUG_MODE) { 8093c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 8103c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 8113c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka final float radiusRatio = 8123c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mBogusMoveEventDetector.getDistanceFromDownEvent(x, y) 8133c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka / keyDiagonal; 8143c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 8153c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " bogus down-move-up event (raidus=%.2f key diagonal) is " 8163c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka + " translated to up[%d,%d,%s]/down[%d,%d,%s] events", 8173c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka mPointerId, radiusRatio, 8187dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka lastX, lastY, Constants.printableCode(oldKey.getCode()), 8197dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka x, y, Constants.printableCode(key.getCode()))); 8203c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 82135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 8223c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka onDownEventInternal(x, y, eventTime); 8233c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 8243c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka 8252fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private void processDraggingFingerOutFromOldKey(final Key oldKey) { 82653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka setReleasedKeyGraphics(oldKey, true /* withAnimation */); 8277dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.getCode(), true /* withSliding */); 8282fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa startKeySelectionByDraggingFinger(oldKey); 8292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sTimerProxy.cancelKeyTimersOf(this); 830831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } 831831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka 8322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private void dragFingerFromOldKeyToNewKey(final Key key, final int x, final int y, 8338b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final long eventTime, final Key oldKey, final int lastX, final int lastY) { 8348b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 8358b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 8368b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // onPress() to notify that the new key is being pressed. 8372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa processDraggingFingerOutFromOldKey(oldKey); 8388b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka startRepeatKey(key); 8392fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (mIsAllowedDraggingFinger) { 8402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa processDraggingFingerInToNewKey(key, x, y, eventTime); 8412a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 8422a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be reported as a sudden move by 8432a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // touch panel firmware. This hack detects such cases and translates the move event to 8442a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // successive up and down events. 8452a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // TODO: Should find a way to balance gesture detection and this hack. 8462a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka else if (sNeedsPhantomSuddenMoveEventHack 8472fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa && getDistance(x, y, lastX, lastY) >= mPhantomSuddenMoveThreshold) { 8482a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processPhantomSuddenMoveHack(key, x, y, eventTime, oldKey, lastX, lastY); 8492a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 8502a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: On some devices, quick successive proximate touches may be reported as a bogus 8512a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // down-move-up event by touch panel firmware. This hack detects such cases and breaks 8522a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // these events into separate up and down events. 853c986d16e8aa97c042e1791cabb0a79bb9aaf04a1Tadashi G. Takaoka else if (sTypingTimeRecorder.isInFastTyping(eventTime) 8542a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { 8552a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY); 8562a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } 8572a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // HACK: If there are currently multiple touches, register the key even if the finger 8582a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // slides off the key. This defends against noise from some touch panels when there are 8592a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // close multiple touches. 8602a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka // Caveat: When in chording input mode with a modifier key, we don't use this hack. 86193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka else if (getActivePointerTrackerCount() > 1 8622a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { 8632a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (DEBUG_MODE) { 8642a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka Log.w(TAG, String.format("[%d] onMoveEvent:" 8652a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka + " detected sliding finger while multi touching", mPointerId)); 8663c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } 8672a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka onUpEvent(x, y, eventTime); 86813d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 86953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka setReleasedKeyGraphics(oldKey, true /* withAnimation */); 8702a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka } else { 8712a3b15b267f4a4c43a2d3f47241c489b9cd94d41Tadashi G. Takaoka if (!mIsDetectingGesture) { 87213d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 8738b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 87453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka setReleasedKeyGraphics(oldKey, true /* withAnimation */); 8758b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 8768b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 8778b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 8782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private void dragFingerOutFromOldKey(final Key oldKey, final int x, final int y) { 8798b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 8808b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka // notify that the previous key has been released. 8812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa processDraggingFingerOutFromOldKey(oldKey); 8822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (mIsAllowedDraggingFinger) { 8838b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onMoveToNewKey(null, x, y); 8848b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } else { 8858b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (!mIsDetectingGesture) { 88613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 8878b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 8888b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 8898b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka } 8908b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka 8916c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka private void onMoveEventInternal(final int x, final int y, final long eventTime) { 8928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 8938a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 894e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key oldKey = mCurrentKey; 8958b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka final Key newKey = onMoveKey(x, y); 896eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 897a00838b6e8d7b3ebb55b26cccc84a1763f88f0a9Tadashi G. Takaoka if (sGestureEnabler.shouldHandleGesture()) { 8986c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka // Register move event on gesture tracker. 8998b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey); 9006c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 9016c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 90253b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka setReleasedKeyGraphics(oldKey, true /* withAnimation */); 9036c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 9046c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 905eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 906eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 9078b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (newKey != null) { 9083c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 9092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa dragFingerFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY); 9103c6d3a4df8b23b091c34ee3590268d469d46cbeeTadashi G. Takaoka } else if (oldKey == null) { 911831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 912831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 9132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa processDraggingFingerInToNewKey(newKey, x, y, eventTime); 914c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 915831198a4e4295bcdae44b7d00686b8a93aed720bTadashi G. Takaoka } else { // newKey == null 9168b449c6dda88174ec19bfc366baf048a72857215Tadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { 9172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa dragFingerOutFromOldKey(oldKey, x, y); 91807221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 9196a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (mIsInSlidingKeyInput) { 9212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sDrawingProxy.showSlidingKeyInputPreview(this); 922212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 9236a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 9246a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 925e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka private void onUpEvent(final int x, final int y, final long eventTime) { 926694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 927dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 928694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 9291d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 9302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sTimerProxy.cancelUpdateBatchInputTimer(this); 93193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (!sInGesture) { 93293b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka if (mCurrentKey != null && mCurrentKey.isModifier()) { 93393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // Before processing an up event of modifier key, all pointers already being 93493b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka // tracked should be released. 93593b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime); 93693b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka } else { 93793b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime); 9381d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9391d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 94035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(x, y, eventTime); 94193b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 9421d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9431d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 944d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 945d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 946d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 9470cc425bd9c476d3cb6708554282a3242019eb317Tadashi G. Takaoka @Override 948694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka public void onPhantomUpEvent(final long eventTime) { 949694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 950547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka printTouchEvent("onPhntEvent:", mLastX, mLastY, eventTime); 951694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 95235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang onUpEventInternal(mLastX, mLastY, eventTime); 95313d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 9541d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 9551d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 95635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang private void onUpEventInternal(final int x, final int y, final long eventTime) { 9572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sTimerProxy.cancelKeyTimersOf(this); 9582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final boolean isInDraggingFinger = mIsInDraggingFinger; 959e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka final boolean isInSlidingKeyInput = mIsInSlidingKeyInput; 9602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa resetKeySelectionByDraggingFinger(); 9616c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mIsDetectingGesture = false; 9626c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final Key currentKey = mCurrentKey; 9636c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mCurrentKey = null; 964a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka final int currentRepeatingKeyCode = mCurrentRepeatingKeyCode; 965a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka mCurrentRepeatingKeyCode = Constants.NOT_A_CODE; 9665a40dcaf8b6250eeea241471e54e8fe856cdf19bTadashi G. Takaoka // Release the last pressed key. 96753b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka setReleasedKeyGraphics(currentKey, true /* withAnimation */); 96835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 96935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang if (isShowingMoreKeysPanel()) { 97013d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (!mIsTrackingForActionDisabled) { 97135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedX = mMoreKeysPanel.translateX(x); 97235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int translatedY = mMoreKeysPanel.translateY(y); 97335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreKeysPanel.onUpEvent(translatedX, translatedY, mPointerId, eventTime); 97435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang } 975fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka dismissMoreKeysPanel(); 97635580bad6f3da3b204653825bbb6871563e70728Tom Ouyang return; 9779ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 978eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 9796c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (sInGesture) { 9806c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (currentKey != null) { 9817dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka callListenerOnRelease(currentKey, currentKey.getCode(), true /* withSliding */); 982eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 9834a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka if (mBatchInputArbiter.mayEndBatchInput( 9844a4b6d42a79779fe2a1eaf9c251cf98ab6fdccb5Tadashi G. Takaoka eventTime, getActivePointerTrackerCount(), this)) { 985904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka sInGesture = false; 986904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka } 987904866c701cd1708f1a2a31e53dfc262ec3eb2b5Tadashi G. Takaoka showGestureTrail(); 988eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang return; 989eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 99058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 99113d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka if (mIsTrackingForActionDisabled) { 992d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 993694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 994a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka if (currentKey != null && currentKey.isRepeatable() 9952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa && (currentKey.getCode() == currentRepeatingKeyCode) && !isInDraggingFinger) { 996e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka return; 9976a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 998e3b1bdc4f18f77f54b33776ad698d57970acd722Tadashi G. Takaoka detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime); 9992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (isInSlidingKeyInput) { 100041016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka callListenerOnFinishSlidingInput(); 100141016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 10026a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10036a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1004b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka @Override 100513d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka public void cancelTrackingForAction() { 10068353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka if (isShowingMoreKeysPanel()) { 10078353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka return; 10088353e751cae4a26d186fb645e9d3d40e1bc5d14bTadashi G. Takaoka } 100913d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka mIsTrackingForActionDisabled = true; 1010b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1011b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 101262316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka public boolean isInOperation() { 101362316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka return !mIsTrackingForActionDisabled; 101462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka } 101562316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka 101653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka public void onLongPressed() { 101734a9e2ae87c6718d439b294d9536b6587a4f89f8Tadashi G. Takaoka sTimerProxy.cancelLongPressTimersOf(this); 101853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 101953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka return; 102053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka } 102153b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka final Key key = getKey(); 102253b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka if (key == null) { 102353b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka return; 102453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka } 102553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka if (key.hasNoPanelAutoMoreKey()) { 102653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka cancelKeyTracking(); 102753b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka final int moreKeyCode = key.getMoreKeys()[0].mCode; 102853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sListener.onPressKey(moreKeyCode, 0 /* repeatCont */, true /* isSinglePointer */); 102953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sListener.onCodeInput(moreKeyCode, Constants.NOT_A_COORDINATE, 103053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka Constants.NOT_A_COORDINATE, false /* isKeyRepeat */); 103153b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sListener.onReleaseKey(moreKeyCode, false /* withSliding */); 103253b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka return; 103353b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka } 103453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka final int code = key.getCode(); 103553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) { 103653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka // Long pressing the space key invokes IME switcher dialog. 103753b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka if (sListener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) { 103853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka cancelKeyTracking(); 103953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka sListener.onReleaseKey(code, false /* withSliding */); 104053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka return; 104153b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka } 104253b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka } 104353b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka 104453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka setReleasedKeyGraphics(key, false /* withAnimation */); 104553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = sDrawingProxy.showMoreKeysKeyboard(key, this); 104653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka if (moreKeysPanel == null) { 104753b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka return; 104853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka } 104953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(mLastX); 105053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(mLastY); 105153b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka moreKeysPanel.onDownEvent(translatedX, translatedY, mPointerId, SystemClock.uptimeMillis()); 105253b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka mMoreKeysPanel = moreKeysPanel; 105362316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka } 105462316d7e821fa3a1ed052eb1ac2e8c0d08931d3eTadashi G. Takaoka 105553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka private void cancelKeyTracking() { 10562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa resetKeySelectionByDraggingFinger(); 105713d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka cancelTrackingForAction(); 105853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey, true /* withAnimation */); 105993b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka sPointerTrackerQueue.remove(this); 1060d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 1061d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 1062e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka private void onCancelEvent(final int x, final int y, final long eventTime) { 1063694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka if (DEBUG_EVENT) { 1064dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 1065694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka } 10661d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 10677c1e853387f71235fd0bd8051246f7a95be5ed53Tadashi G. Takaoka cancelBatchInput(); 10685c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka cancelAllPointerTrackers(); 10698e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka sPointerTrackerQueue.releaseAllPointers(eventTime); 1070baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 10711d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 10721d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 1073baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 10742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sTimerProxy.cancelKeyTimersOf(this); 107553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka setReleasedKeyGraphics(mCurrentKey, true /* withAnimation */); 10762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa resetKeySelectionByDraggingFinger(); 1077fa9b9578d44748de512c947651010e703c663936Tadashi G. Takaoka dismissMoreKeysPanel(); 10786a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 10796a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1080b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, 1081b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka final Key newKey) { 1082694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final Key curKey = mCurrentKey; 10836a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 1084e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 1085a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1086a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (curKey == null /* && newKey != null */) { 1087a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1088a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1089a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka // Here curKey points to the different key from newKey. 1090a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( 10912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mIsInSlidingKeyInput); 1092a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); 1093a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { 1094a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1095a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float distanceToEdgeRatio = (float)Math.sqrt(distanceFromKeyEdgeSquared) 1096a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka / mKeyboard.mMostCommonKeyWidth; 1097a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1098a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka +" %.2f key width from key edge", mPointerId, distanceToEdgeRatio)); 1099b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1100a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return true; 1101a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka } 1102c986d16e8aa97c042e1791cabb0a79bb9aaf04a1Tadashi G. Takaoka if (!mIsAllowedDraggingFinger && sTypingTimeRecorder.isInFastTyping(eventTime) 1103a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) { 1104a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka if (DEBUG_MODE) { 1105a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float keyDiagonal = (float)Math.hypot( 1106a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); 1107a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka final float lengthFromDownRatio = 1108c986d16e8aa97c042e1791cabb0a79bb9aaf04a1Tadashi G. Takaoka mBogusMoveEventDetector.getAccumulatedDistanceFromDownKey() / keyDiagonal; 1109a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" 1110a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka + " %.2f key diagonal from virtual down point", 1111a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka mPointerId, lengthFromDownRatio)); 1112b0952888ebabc5c1fe7c3149d38e4350c890a0a0Tadashi G. Takaoka } 1113e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 11146a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1115a232930d9cfb4a9710eb57735b4a3fe722d64a2bTadashi G. Takaoka return false; 11166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11176a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1118694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void startLongPressTimer(final Key key) { 11191b5b0a3ebc80c24120a8fd5ba45497127b93d238Tadashi G. Takaoka // Note that we need to cancel all active long press shift key timers if any whenever we 11201b5b0a3ebc80c24120a8fd5ba45497127b93d238Tadashi G. Takaoka // start a new long press timer for both non-shift and shift keys. 112134a9e2ae87c6718d439b294d9536b6587a4f89f8Tadashi G. Takaoka sTimerProxy.cancelLongPressShiftKeyTimer(); 112243ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (sInGesture) return; 112343ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (key == null) return; 112443ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka if (!key.isLongPressEnabled()) return; 112543ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // Caveat: Please note that isLongPressEnabled() can be true even if the current key 11262fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // doesn't have its more keys. (e.g. spacebar, globe key) If we are in the dragging finger 11272fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // mode, we will disable long press timer of such key. 112843ad100d8bc20fc1327a462f24b5f8c99849ffbeTadashi G. Takaoka // We always need to start the long press timer if the key has its more keys regardless of 11292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // whether or not we are in the dragging finger mode. 11302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (mIsInDraggingFinger && key.getMoreKeys() == null) return; 11312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 11322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int delay = getLongPressTimeout(key.getCode()); 11331b5b0a3ebc80c24120a8fd5ba45497127b93d238Tadashi G. Takaoka if (delay <= 0) return; 11342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sTimerProxy.startLongPressTimerOf(this, delay); 11352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 11362fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 11372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private int getLongPressTimeout(final int code) { 11382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (code == Constants.CODE_SHIFT) { 11392fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return sParams.mLongPressShiftLockTimeout; 11402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 11412fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int longpressTimeout = Settings.getInstance().getCurrent().mKeyLongpressTimeout; 11422fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (mIsInSlidingKeyInput) { 11432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // We use longer timeout for sliding finger input started from the modifier key. 11442fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return longpressTimeout * MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT; 1145212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 11462fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return longpressTimeout; 114766e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 114866e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 11493623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) { 115083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 11518aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 1152dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 1153dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 115466e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 11557dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int code = key.getCode(); 11562282e8520a2c1984989a14fb09896536f5033b26Jean Chalard callListenerOnCodeInput(key, code, x, y, eventTime, false /* isKeyRepeat */); 115741016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka callListenerOnRelease(key, code, false /* withSliding */); 11586a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 11596a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 11608126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka private void startRepeatKey(final Key key) { 11618126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka if (sInGesture) return; 11628126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka if (key == null) return; 11638126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka if (!key.isRepeatable()) return; 11642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Don't start key repeat when we are in the dragging finger mode. 11652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (mIsInDraggingFinger) return; 1166ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka final int startRepeatCount = 1; 11672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa startKeyRepeatTimer(startRepeatCount); 11688126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka } 11698126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka 1170ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka public void onKeyRepeat(final int code, final int repeatCount) { 11718126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka final Key key = getKey(); 11727dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka if (key == null || key.getCode() != code) { 1173a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka mCurrentRepeatingKeyCode = Constants.NOT_A_CODE; 11748126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka return; 11758126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka } 1176a456e3f659e03c5a36b87e318a10d469520cf72bSatoshi Kataoka mCurrentRepeatingKeyCode = code; 11770938fb6913c10d32f0a870210fc208c7bbfe282cSatoshi Kataoka mIsDetectingGesture = false; 1178ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka final int nextRepeatCount = repeatCount + 1; 11792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa startKeyRepeatTimer(nextRepeatCount); 1180ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka callListenerOnPressAndCheckKeyboardLayoutChange(key, repeatCount); 11812282e8520a2c1984989a14fb09896536f5033b26Jean Chalard callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis(), 11822282e8520a2c1984989a14fb09896536f5033b26Jean Chalard true /* isKeyRepeat */); 11838126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka } 11848126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka 11852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private void startKeyRepeatTimer(final int repeatCount) { 11862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int delay = 11872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa (repeatCount == 1) ? sParams.mKeyRepeatStartTimeout : sParams.mKeyRepeatInterval; 11882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa sTimerProxy.startKeyRepeatTimerOf(this, repeatCount, delay); 11892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 11902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 1191694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka private void printTouchEvent(final String title, final int x, final int y, 1192694ccb5ba1bb61caea379487c6bdfae7c64c2643Tadashi G. Takaoka final long eventTime) { 1193723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka final Key key = mKeyDetector.detectHitKey(x, y); 11949fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka final String code = (key == null ? "none" : Constants.printableCode(key.getCode())); 119558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, 119613d5da8b8819866bd2ef1aac6eadc74305bf8d55Tadashi G. Takaoka (mIsTrackingForActionDisabled ? "-" : " "), title, x, y, eventTime, code)); 1197dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 11986e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 1199