GestureStrokeRecognitionPoints.java revision 915f348b35cb66ed9696a51c9250f9b25799fb82
1f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka/* 2f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project 3f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * 4f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * in compliance with the License. You may obtain a copy of the License at 6f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * 7f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 8f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * 9f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software distributed under the License 10f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * or implied. See the License for the specific language governing permissions and limitations under 12f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * the License. 13f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka */ 14f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 15f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokapackage com.android.inputmethod.keyboard.internal; 16f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 1780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport android.content.res.TypedArray; 1802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaokaimport android.util.Log; 1902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 20f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 2180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport com.android.inputmethod.latin.R; 227519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaokaimport com.android.inputmethod.latin.ResizableIntArray; 2380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils; 24f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 25f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokapublic class GestureStroke { 2602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private static final String TAG = GestureStroke.class.getSimpleName(); 2702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private static final boolean DEBUG = false; 2858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static final boolean DEBUG_SPEED = false; 2902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 30b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka // The height of extra area above the keyboard to draw gesture trails. 31b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka // Proportional to the keyboard height. 32b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f; 33b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 3457f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka public static final int DEFAULT_CAPACITY = 128; 3557f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka 36f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka private final int mPointerId; 377519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY); 387519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); 397519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); 4002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 4180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private final GestureStrokeParams mParams; 4280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka 4358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mKeyWidth; // pixel 44b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka private int mMinYCoordinate; // pixel 45b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka private int mMaxYCoordinate; // pixel 4658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Static threshold for starting gesture detection 4702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int mDetectFastMoveSpeedThreshold; // pixel /sec 4802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int mDetectFastMoveTime; 4902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int mDetectFastMoveX; 5002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int mDetectFastMoveY; 5158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Dynamic threshold for gesture after fast typing 5258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private boolean mAfterFastTyping; 5358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mGestureDynamicDistanceThresholdFrom; // pixel 5458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mGestureDynamicDistanceThresholdTo; // pixel 5558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Variables for gesture sampling 5658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mGestureSamplingMinimumDistance; // pixel 5758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private long mLastMajorEventTime; 5858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mLastMajorEventX; 5958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mLastMajorEventY; 6058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Variables for gesture recognition 6158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mGestureRecognitionSpeedThreshold; // pixel / sec 6258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mIncrementalRecognitionSize; 6358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mLastIncrementalBatchSize; 64f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 6580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public static final class GestureStrokeParams { 6680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Static threshold for gesture after fast typing 6780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mStaticTimeThresholdAfterFastTyping; // msec 6880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Static threshold for starting gesture detection 6980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mDetectFastMoveSpeedThreshold; // keyWidth/sec 7080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Dynamic threshold for gesture after fast typing 7180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mDynamicThresholdDecayDuration; // msec 7280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Time based threshold values 7380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mDynamicTimeThresholdFrom; // msec 7480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mDynamicTimeThresholdTo; // msec 7580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Distance based threshold values 7680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mDynamicDistanceThresholdFrom; // keyWidth 7780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mDynamicDistanceThresholdTo; // keyWidth 7880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Parameters for gesture sampling 7980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mSamplingMinimumDistance; // keyWidth 8080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Parameters for gesture recognition 8180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mRecognitionMinimumTime; // msec 8280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mRecognitionSpeedThreshold; // keyWidth/sec 8358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 8480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Default GestureStroke parameters for test. 8580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public static final GestureStrokeParams FOR_TEST = new GestureStrokeParams(); 8680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public static final GestureStrokeParams DEFAULT = FOR_TEST; 8758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 8880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private GestureStrokeParams() { 8980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // These parameter values are default and intended for testing. 9080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = 350; // msec 9180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDetectFastMoveSpeedThreshold = 1.5f; // keyWidth / sec 9280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicThresholdDecayDuration = 450; // msec 9380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicTimeThresholdFrom = 300; // msec 9480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicTimeThresholdTo = 20; // msec 9580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicDistanceThresholdFrom = 6.0f; // keyWidth 9680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicDistanceThresholdTo = 0.35f; // keyWidth 9780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // The following parameters' change will affect the result of regression test. 9880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mSamplingMinimumDistance = 1.0f / 6.0f; // keyWidth 9980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mRecognitionMinimumTime = 100; // msec 10080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mRecognitionSpeedThreshold = 5.5f; // keyWidth / sec 10180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka } 10258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 10380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public GestureStrokeParams(final TypedArray mainKeyboardViewAttr) { 10480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = mainKeyboardViewAttr.getInt( 10580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping, 10680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mStaticTimeThresholdAfterFastTyping); 10780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDetectFastMoveSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr, 10880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDetectFastMoveSpeedThreshold, 10980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDetectFastMoveSpeedThreshold); 11080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicThresholdDecayDuration = mainKeyboardViewAttr.getInt( 11180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicThresholdDecayDuration, 11280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicThresholdDecayDuration); 11380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicTimeThresholdFrom = mainKeyboardViewAttr.getInt( 11480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicTimeThresholdFrom, 11580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicTimeThresholdFrom); 11680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicTimeThresholdTo = mainKeyboardViewAttr.getInt( 11780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicTimeThresholdTo, 11880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicTimeThresholdTo); 11980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicDistanceThresholdFrom = ResourceUtils.getFraction(mainKeyboardViewAttr, 12080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdFrom, 12180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicDistanceThresholdFrom); 12280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicDistanceThresholdTo = ResourceUtils.getFraction(mainKeyboardViewAttr, 12380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdTo, 12480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicDistanceThresholdTo); 12580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mSamplingMinimumDistance = ResourceUtils.getFraction(mainKeyboardViewAttr, 12680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureSamplingMinimumDistance, 12780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mSamplingMinimumDistance); 12880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mRecognitionMinimumTime = mainKeyboardViewAttr.getInt( 12980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureRecognitionMinimumTime, 13080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mRecognitionMinimumTime); 13180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mRecognitionSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr, 13280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureRecognitionSpeedThreshold, 13380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mRecognitionSpeedThreshold); 13480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka } 13580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka } 13658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 13758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static final int MSEC_PER_SEC = 1000; 138f80f09c7eed430827ae8294a5b0f33d5f21cee60Tadashi G. Takaoka 13980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public GestureStroke(final int pointerId, final GestureStrokeParams params) { 140f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka mPointerId = pointerId; 14180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mParams = params; 142f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 143f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 144b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { 14502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mKeyWidth = keyWidth; 146b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mMinYCoordinate = -(int)(keyboardHeight * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); 147b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mMaxYCoordinate = keyboardHeight - 1; 1481e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? 14980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDetectFastMoveSpeedThreshold = (int)(keyWidth * mParams.mDetectFastMoveSpeedThreshold); 15058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureDynamicDistanceThresholdFrom = 15180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka (int)(keyWidth * mParams.mDynamicDistanceThresholdFrom); 15280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureDynamicDistanceThresholdTo = (int)(keyWidth * mParams.mDynamicDistanceThresholdTo); 15380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureSamplingMinimumDistance = (int)(keyWidth * mParams.mSamplingMinimumDistance); 15480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureRecognitionSpeedThreshold = (int)(keyWidth * mParams.mRecognitionSpeedThreshold); 15502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (DEBUG) { 15658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format( 15758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka "[%d] setKeyboardGeometry: keyWidth=%3d tT=%3d >> %3d tD=%3d >> %3d", 15858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, keyWidth, 15980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mParams.mDynamicTimeThresholdFrom, 16080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mParams.mDynamicTimeThresholdTo, 16158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureDynamicDistanceThresholdFrom, 16258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureDynamicDistanceThresholdTo)); 16302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 164f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 165f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 16658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka public void onDownEvent(final int x, final int y, final long downTime, 16758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final long gestureFirstDownTime, final long lastTypingTime) { 16858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka reset(); 16958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final long elapsedTimeAfterTyping = downTime - lastTypingTime; 17080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka if (elapsedTimeAfterTyping < mParams.mStaticTimeThresholdAfterFastTyping) { 171630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka mAfterFastTyping = true; 172630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 173630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka if (DEBUG) { 17458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onDownEvent: dT=%3d%s", mPointerId, 17558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : "")); 176630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 17758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime); 178b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka addPointOnKeyboard(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); 179630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 180630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka 18158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int getGestureDynamicDistanceThreshold(final int deltaTime) { 18280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka if (!mAfterFastTyping || deltaTime >= mParams.mDynamicThresholdDecayDuration) { 18358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return mGestureDynamicDistanceThresholdTo; 184630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 185630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka final int decayedThreshold = 18658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka (mGestureDynamicDistanceThresholdFrom - mGestureDynamicDistanceThresholdTo) 18780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka * deltaTime / mParams.mDynamicThresholdDecayDuration; 18858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return mGestureDynamicDistanceThresholdFrom - decayedThreshold; 18958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 19058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 19158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int getGestureDynamicTimeThreshold(final int deltaTime) { 19280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka if (!mAfterFastTyping || deltaTime >= mParams.mDynamicThresholdDecayDuration) { 19380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka return mParams.mDynamicTimeThresholdTo; 19458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 19558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int decayedThreshold = 19680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka (mParams.mDynamicTimeThresholdFrom - mParams.mDynamicTimeThresholdTo) 19780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka * deltaTime / mParams.mDynamicThresholdDecayDuration; 19880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka return mParams.mDynamicTimeThresholdFrom - decayedThreshold; 199630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 200630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka 2017a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka public final boolean isStartOfAGesture() { 2027a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (!hasDetectedFastMove()) { 20302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return false; 20402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 20574d0bb09c700aec91afd120688c56498d93e3110Tadashi G. Takaoka final int size = mEventTimes.getLength(); 20602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (size <= 0) { 20702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return false; 20802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 20902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int lastIndex = size - 1; 21002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int deltaTime = mEventTimes.get(lastIndex) - mDetectFastMoveTime; 2117a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (deltaTime < 0) { 2127a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return false; 2137a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka } 21458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int deltaDistance = getDistance( 21502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex), 21602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveX, mDetectFastMoveY); 21758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int distanceThreshold = getGestureDynamicDistanceThreshold(deltaTime); 21858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int timeThreshold = getGestureDynamicTimeThreshold(deltaTime); 21958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final boolean isStartOfAGesture = deltaTime >= timeThreshold 22058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka && deltaDistance >= distanceThreshold; 22102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (DEBUG) { 22258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] isStartOfAGesture: dT=%3d tT=%3d dD=%3d tD=%3d%s%s", 22358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, deltaTime, timeThreshold, 22458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka deltaDistance, distanceThreshold, 22558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mAfterFastTyping ? " afterFastTyping" : "", 22658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka isStartOfAGesture ? " startOfAGesture" : "")); 22702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 22802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return isStartOfAGesture; 229f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 230f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 23172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void duplicateLastPointWith(final int time) { 23272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int lastIndex = mEventTimes.getLength() - 1; 23372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (lastIndex >= 0) { 23472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int x = mXCoordinates.get(lastIndex); 23572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int y = mYCoordinates.get(lastIndex); 236915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka if (DEBUG) { 237915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka Log.d(TAG, String.format("[%d] duplicateLastPointWith: %d,%d|%d", mPointerId, 238915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka x, y, time)); 239915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka } 24072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka // TODO: Have appendMajorPoint() 24172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka appendPoint(x, y, time); 24272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka updateIncrementalRecognitionSize(x, y, time); 24372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 24472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 24572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 24658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka protected void reset() { 2471e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka mIncrementalRecognitionSize = 0; 2480c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang mLastIncrementalBatchSize = 0; 2497519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka mEventTimes.setLength(0); 2507519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka mXCoordinates.setLength(0); 2517519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka mYCoordinates.setLength(0); 25202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mLastMajorEventTime = 0; 25302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveTime = 0; 254630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka mAfterFastTyping = false; 25502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 25602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 25702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private void appendPoint(final int x, final int y, final int time) { 258915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka final int lastIndex = mEventTimes.getLength() - 1; 259915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka // The point that is created by {@link duplicateLastPointWith(int)} may have later event 260915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka // time than the next {@link MotionEvent}. To maintain the monotonicity of the event time, 261915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka // drop the successive point here. 262915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka if (lastIndex >= 0 && mEventTimes.get(lastIndex) > time) { 263915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka Log.w(TAG, String.format("[%d] drop stale event: %d,%d|%d last: %d,%d|%d", mPointerId, 264915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka x, y, time, mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex), 265915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka mEventTimes.get(lastIndex))); 266915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka return; 267915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka } 26802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mEventTimes.add(time); 26902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mXCoordinates.add(x); 27002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mYCoordinates.add(y); 271f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 272f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 27302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private void updateMajorEvent(final int x, final int y, final int time) { 27402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mLastMajorEventTime = time; 27502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mLastMajorEventX = x; 27602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mLastMajorEventY = y; 27702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 27802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 279c9ba26994b946d35c375cd1cd9a6db2b23b3de7eTadashi G. Takaoka private final boolean hasDetectedFastMove() { 2807a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return mDetectFastMoveTime > 0; 2817a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka } 2827a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka 28302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int detectFastMove(final int x, final int y, final int time) { 2847519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka final int size = mEventTimes.getLength(); 28502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int lastIndex = size - 1; 28602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int lastX = mXCoordinates.get(lastIndex); 28702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int lastY = mYCoordinates.get(lastIndex); 28802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int dist = getDistance(lastX, lastY, x, y); 28902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int msecs = time - mEventTimes.get(lastIndex); 29002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (msecs > 0) { 29102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int pixels = getDistance(lastX, lastY, x, y); 29202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int pixelsPerSec = pixels * MSEC_PER_SEC; 29358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (DEBUG_SPEED) { 29402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final float speed = (float)pixelsPerSec / msecs / mKeyWidth; 29558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] detectFastMove: speed=%5.2f", mPointerId, speed)); 29602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 29702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka // Equivalent to (pixels / msecs < mStartSpeedThreshold / MSEC_PER_SEC) 2987a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (!hasDetectedFastMove() && pixelsPerSec > mDetectFastMoveSpeedThreshold * msecs) { 29902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (DEBUG) { 30058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final float speed = (float)pixelsPerSec / msecs / mKeyWidth; 30158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format( 30258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka "[%d] detectFastMove: speed=%5.2f T=%3d points=%3d fastMove", 30358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, speed, time, size)); 30402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 30502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveTime = time; 30602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveX = x; 30702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveY = y; 30802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 309f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 31002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return dist; 31102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 31202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 313b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka /** 314b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * Add a touch event as a gesture point. Returns true if the touch event is on the valid 315b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * gesture area. 316b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @param x the x-coordinate of the touch event 317b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @param y the y-coordinate of the touch event 318b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @param time the elapsed time in millisecond from the first gesture down 319b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @param isMajorEvent false if this is a historical move event 320b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @return true if the touch event is on the valid gesture area 321b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka */ 322b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public boolean addPointOnKeyboard(final int x, final int y, final int time, 323b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka final boolean isMajorEvent) { 32402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int size = mEventTimes.getLength(); 32502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (size <= 0) { 32602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka // Down event 32702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka appendPoint(x, y, time); 32802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka updateMajorEvent(x, y, time); 32902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } else { 33058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int distance = detectFastMove(x, y, time); 33158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (distance > mGestureSamplingMinimumDistance) { 33202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka appendPoint(x, y, time); 33302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 334f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 33502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (isMajorEvent) { 33661dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka updateIncrementalRecognitionSize(x, y, time); 33702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka updateMajorEvent(x, y, time); 33861dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka } 339b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka return y >= mMinYCoordinate && y < mMaxYCoordinate; 34061dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka } 34161dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka 34261dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka private void updateIncrementalRecognitionSize(final int x, final int y, final int time) { 34302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int msecs = (int)(time - mLastMajorEventTime); 34402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (msecs <= 0) { 34502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return; 34602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 34702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int pixels = getDistance(mLastMajorEventX, mLastMajorEventY, x, y); 34802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int pixelsPerSec = pixels * MSEC_PER_SEC; 34902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka // Equivalent to (pixels / msecs < mGestureRecognitionThreshold / MSEC_PER_SEC) 35002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (pixelsPerSec < mGestureRecognitionSpeedThreshold * msecs) { 35102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mIncrementalRecognitionSize = mEventTimes.getLength(); 352f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 35358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 35458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 35580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final boolean hasRecognitionTimePast( 35658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final long currentTime, final long lastRecognitionTime) { 35780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka return currentTime > lastRecognitionTime + mParams.mRecognitionMinimumTime; 358f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 359f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 3607a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka public final void appendAllBatchPoints(final InputPointers out) { 3617519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka appendBatchPoints(out, mEventTimes.getLength()); 362f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 363f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 3647a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka public final void appendIncrementalBatchPoints(final InputPointers out) { 3657519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka appendBatchPoints(out, mIncrementalRecognitionSize); 3667519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka } 3677519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka 3687519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka private void appendBatchPoints(final InputPointers out, final int size) { 3696c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int length = size - mLastIncrementalBatchSize; 3706c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (length <= 0) { 3716c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 3726c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 3737519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka out.append(mPointerId, mEventTimes, mXCoordinates, mYCoordinates, 3746c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mLastIncrementalBatchSize, length); 3757519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka mLastIncrementalBatchSize = size; 376f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 377f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 37802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private static int getDistance(final int x1, final int y1, final int x2, final int y2) { 37902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int dx = x1 - x2; 38002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int dy = y1 - y2; 381bcec82de66f52655593dc233346f11468f5077a0Ken Wakasa // Note that, in recent versions of Android, FloatMath is actually slower than 382bcec82de66f52655593dc233346f11468f5077a0Ken Wakasa // java.lang.Math due to the way the JIT optimizes java.lang.Math. 38302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return (int)Math.sqrt(dx * dx + dy * dy); 384f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 385f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka} 386