GestureStrokeRecognitionPoints.java revision 8aa9963a895f9dd5bb1bc92ab2e4f461e058f87a
1f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka/* 2f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project 3f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi 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 7f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * 88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 9f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka * 108aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi 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. 15f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka */ 16f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 17f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokapackage com.android.inputmethod.keyboard.internal; 18f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 1980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport android.content.res.TypedArray; 2002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaokaimport android.util.Log; 2102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 22f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokaimport com.android.inputmethod.latin.InputPointers; 2380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport com.android.inputmethod.latin.R; 247519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaokaimport com.android.inputmethod.latin.ResizableIntArray; 2580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils; 26f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 27f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaokapublic class GestureStroke { 2802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private static final String TAG = GestureStroke.class.getSimpleName(); 2902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private static final boolean DEBUG = false; 3058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static final boolean DEBUG_SPEED = false; 3102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 32b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka // The height of extra area above the keyboard to draw gesture trails. 33b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka // Proportional to the keyboard height. 34b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f; 35b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 3657f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka public static final int DEFAULT_CAPACITY = 128; 3757f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka 38f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka private final int mPointerId; 397519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY); 407519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); 417519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); 4202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 4380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private final GestureStrokeParams mParams; 4480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka 4558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mKeyWidth; // pixel 46b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka private int mMinYCoordinate; // pixel 47b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka private int mMaxYCoordinate; // pixel 4858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Static threshold for starting gesture detection 4902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int mDetectFastMoveSpeedThreshold; // pixel /sec 5002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int mDetectFastMoveTime; 5102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int mDetectFastMoveX; 5202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int mDetectFastMoveY; 5358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Dynamic threshold for gesture after fast typing 5458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private boolean mAfterFastTyping; 5558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mGestureDynamicDistanceThresholdFrom; // pixel 5658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mGestureDynamicDistanceThresholdTo; // pixel 5758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Variables for gesture sampling 5858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mGestureSamplingMinimumDistance; // pixel 5958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private long mLastMajorEventTime; 6058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mLastMajorEventX; 6158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mLastMajorEventY; 6258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Variables for gesture recognition 6358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mGestureRecognitionSpeedThreshold; // pixel / sec 6458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mIncrementalRecognitionSize; 6558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int mLastIncrementalBatchSize; 66f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 6780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public static final class GestureStrokeParams { 6880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Static threshold for gesture after fast typing 6980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mStaticTimeThresholdAfterFastTyping; // msec 7080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Static threshold for starting gesture detection 7180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mDetectFastMoveSpeedThreshold; // keyWidth/sec 7280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Dynamic threshold for gesture after fast typing 7380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mDynamicThresholdDecayDuration; // msec 7480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Time based threshold values 7580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mDynamicTimeThresholdFrom; // msec 7680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mDynamicTimeThresholdTo; // msec 7780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Distance based threshold values 7880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mDynamicDistanceThresholdFrom; // keyWidth 7980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mDynamicDistanceThresholdTo; // keyWidth 8080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Parameters for gesture sampling 8180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mSamplingMinimumDistance; // keyWidth 8280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Parameters for gesture recognition 8380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final int mRecognitionMinimumTime; // msec 8480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final float mRecognitionSpeedThreshold; // keyWidth/sec 8558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 8680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // Default GestureStroke parameters for test. 8780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public static final GestureStrokeParams FOR_TEST = new GestureStrokeParams(); 8880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public static final GestureStrokeParams DEFAULT = FOR_TEST; 8958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 9080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka private GestureStrokeParams() { 9180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // These parameter values are default and intended for testing. 9280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = 350; // msec 9380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDetectFastMoveSpeedThreshold = 1.5f; // keyWidth / sec 9480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicThresholdDecayDuration = 450; // msec 9580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicTimeThresholdFrom = 300; // msec 9680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicTimeThresholdTo = 20; // msec 9780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicDistanceThresholdFrom = 6.0f; // keyWidth 9880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicDistanceThresholdTo = 0.35f; // keyWidth 9980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka // The following parameters' change will affect the result of regression test. 10080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mSamplingMinimumDistance = 1.0f / 6.0f; // keyWidth 10180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mRecognitionMinimumTime = 100; // msec 10280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mRecognitionSpeedThreshold = 5.5f; // keyWidth / sec 10380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka } 10458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 10580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public GestureStrokeParams(final TypedArray mainKeyboardViewAttr) { 10680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mStaticTimeThresholdAfterFastTyping = mainKeyboardViewAttr.getInt( 10780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping, 10880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mStaticTimeThresholdAfterFastTyping); 10980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDetectFastMoveSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr, 11080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDetectFastMoveSpeedThreshold, 11180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDetectFastMoveSpeedThreshold); 11280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicThresholdDecayDuration = mainKeyboardViewAttr.getInt( 11380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicThresholdDecayDuration, 11480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicThresholdDecayDuration); 11580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicTimeThresholdFrom = mainKeyboardViewAttr.getInt( 11680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicTimeThresholdFrom, 11780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicTimeThresholdFrom); 11880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicTimeThresholdTo = mainKeyboardViewAttr.getInt( 11980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicTimeThresholdTo, 12080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicTimeThresholdTo); 12180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicDistanceThresholdFrom = ResourceUtils.getFraction(mainKeyboardViewAttr, 12280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdFrom, 12380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicDistanceThresholdFrom); 12480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDynamicDistanceThresholdTo = ResourceUtils.getFraction(mainKeyboardViewAttr, 12580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdTo, 12680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mDynamicDistanceThresholdTo); 12780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mSamplingMinimumDistance = ResourceUtils.getFraction(mainKeyboardViewAttr, 12880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureSamplingMinimumDistance, 12980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mSamplingMinimumDistance); 13080bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mRecognitionMinimumTime = mainKeyboardViewAttr.getInt( 13180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureRecognitionMinimumTime, 13280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mRecognitionMinimumTime); 13380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mRecognitionSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr, 13480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka R.styleable.MainKeyboardView_gestureRecognitionSpeedThreshold, 13580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka DEFAULT.mRecognitionSpeedThreshold); 13680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka } 13780bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka } 13858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 13958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static final int MSEC_PER_SEC = 1000; 140f80f09c7eed430827ae8294a5b0f33d5f21cee60Tadashi G. Takaoka 14180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public GestureStroke(final int pointerId, final GestureStrokeParams params) { 142f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka mPointerId = pointerId; 14380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mParams = params; 144f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 145f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 146b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { 14702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mKeyWidth = keyWidth; 148b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mMinYCoordinate = -(int)(keyboardHeight * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); 149b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mMaxYCoordinate = keyboardHeight - 1; 1501e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? 15180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mDetectFastMoveSpeedThreshold = (int)(keyWidth * mParams.mDetectFastMoveSpeedThreshold); 15258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureDynamicDistanceThresholdFrom = 15380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka (int)(keyWidth * mParams.mDynamicDistanceThresholdFrom); 15480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureDynamicDistanceThresholdTo = (int)(keyWidth * mParams.mDynamicDistanceThresholdTo); 15580bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureSamplingMinimumDistance = (int)(keyWidth * mParams.mSamplingMinimumDistance); 15680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mGestureRecognitionSpeedThreshold = (int)(keyWidth * mParams.mRecognitionSpeedThreshold); 15702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (DEBUG) { 15858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format( 15958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka "[%d] setKeyboardGeometry: keyWidth=%3d tT=%3d >> %3d tD=%3d >> %3d", 16058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, keyWidth, 16180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mParams.mDynamicTimeThresholdFrom, 16280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka mParams.mDynamicTimeThresholdTo, 16358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureDynamicDistanceThresholdFrom, 16458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mGestureDynamicDistanceThresholdTo)); 16502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 166f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 167f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 168b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka public int getLength() { 169b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka return mEventTimes.getLength(); 170b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka } 171b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka 17258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka public void onDownEvent(final int x, final int y, final long downTime, 17358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final long gestureFirstDownTime, final long lastTypingTime) { 17458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka reset(); 17558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final long elapsedTimeAfterTyping = downTime - lastTypingTime; 17680bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka if (elapsedTimeAfterTyping < mParams.mStaticTimeThresholdAfterFastTyping) { 177630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka mAfterFastTyping = true; 178630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 179630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka if (DEBUG) { 18058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] onDownEvent: dT=%3d%s", mPointerId, 18158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : "")); 182630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 18358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime); 184b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka addPointOnKeyboard(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); 185630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 186630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka 18758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int getGestureDynamicDistanceThreshold(final int deltaTime) { 18880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka if (!mAfterFastTyping || deltaTime >= mParams.mDynamicThresholdDecayDuration) { 18958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return mGestureDynamicDistanceThresholdTo; 190630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 191630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka final int decayedThreshold = 19258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka (mGestureDynamicDistanceThresholdFrom - mGestureDynamicDistanceThresholdTo) 19380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka * deltaTime / mParams.mDynamicThresholdDecayDuration; 19458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return mGestureDynamicDistanceThresholdFrom - decayedThreshold; 19558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 19658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 19758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private int getGestureDynamicTimeThreshold(final int deltaTime) { 19880bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka if (!mAfterFastTyping || deltaTime >= mParams.mDynamicThresholdDecayDuration) { 19980bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka return mParams.mDynamicTimeThresholdTo; 20058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 20158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int decayedThreshold = 20280bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka (mParams.mDynamicTimeThresholdFrom - mParams.mDynamicTimeThresholdTo) 20380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka * deltaTime / mParams.mDynamicThresholdDecayDuration; 20480bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka return mParams.mDynamicTimeThresholdFrom - decayedThreshold; 205630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka } 206630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka 2077a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka public final boolean isStartOfAGesture() { 2087a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (!hasDetectedFastMove()) { 20902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return false; 21002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 211b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka final int size = getLength(); 21202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (size <= 0) { 21302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return false; 21402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 21502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int lastIndex = size - 1; 21602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int deltaTime = mEventTimes.get(lastIndex) - mDetectFastMoveTime; 2177a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (deltaTime < 0) { 2187a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return false; 2197a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka } 22058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int deltaDistance = getDistance( 22102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex), 22202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveX, mDetectFastMoveY); 22358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int distanceThreshold = getGestureDynamicDistanceThreshold(deltaTime); 22458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int timeThreshold = getGestureDynamicTimeThreshold(deltaTime); 22558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final boolean isStartOfAGesture = deltaTime >= timeThreshold 22658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka && deltaDistance >= distanceThreshold; 22702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (DEBUG) { 22858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] isStartOfAGesture: dT=%3d tT=%3d dD=%3d tD=%3d%s%s", 22958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, deltaTime, timeThreshold, 23058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka deltaDistance, distanceThreshold, 23158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mAfterFastTyping ? " afterFastTyping" : "", 23258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka isStartOfAGesture ? " startOfAGesture" : "")); 23302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 23402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return isStartOfAGesture; 235f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 236f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 23772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void duplicateLastPointWith(final int time) { 238b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka final int lastIndex = getLength() - 1; 23972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (lastIndex >= 0) { 24072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int x = mXCoordinates.get(lastIndex); 24172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka final int y = mYCoordinates.get(lastIndex); 242915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka if (DEBUG) { 243915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka Log.d(TAG, String.format("[%d] duplicateLastPointWith: %d,%d|%d", mPointerId, 244915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka x, y, time)); 245915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka } 24672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka // TODO: Have appendMajorPoint() 24772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka appendPoint(x, y, time); 24872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka updateIncrementalRecognitionSize(x, y, time); 24972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 25072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 25172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 25258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka protected void reset() { 2531e6f39a9f994e21b749a1cbae55a3adbfb5640e9Tadashi G. Takaoka mIncrementalRecognitionSize = 0; 2540c5f72e2bf22df48af051827f97ab6052026d531Tom Ouyang mLastIncrementalBatchSize = 0; 2557519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka mEventTimes.setLength(0); 2567519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka mXCoordinates.setLength(0); 2577519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka mYCoordinates.setLength(0); 25802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mLastMajorEventTime = 0; 25902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveTime = 0; 260630d9c95e596c902b80dcb57eb0386e94290406dTadashi G. Takaoka mAfterFastTyping = false; 26102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 26202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 26302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private void appendPoint(final int x, final int y, final int time) { 264b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka final int lastIndex = getLength() - 1; 265915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka // The point that is created by {@link duplicateLastPointWith(int)} may have later event 266915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka // time than the next {@link MotionEvent}. To maintain the monotonicity of the event time, 267915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka // drop the successive point here. 268915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka if (lastIndex >= 0 && mEventTimes.get(lastIndex) > time) { 269915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka Log.w(TAG, String.format("[%d] drop stale event: %d,%d|%d last: %d,%d|%d", mPointerId, 270915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka x, y, time, mXCoordinates.get(lastIndex), mYCoordinates.get(lastIndex), 271915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka mEventTimes.get(lastIndex))); 272915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka return; 273915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka } 27402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mEventTimes.add(time); 27502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mXCoordinates.add(x); 27602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mYCoordinates.add(y); 277f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 278f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 27902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private void updateMajorEvent(final int x, final int y, final int time) { 28002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mLastMajorEventTime = time; 28102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mLastMajorEventX = x; 28202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mLastMajorEventY = y; 28302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 28402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 285c9ba26994b946d35c375cd1cd9a6db2b23b3de7eTadashi G. Takaoka private final boolean hasDetectedFastMove() { 2867a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka return mDetectFastMoveTime > 0; 2877a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka } 2887a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka 28902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private int detectFastMove(final int x, final int y, final int time) { 290b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka final int size = getLength(); 29102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int lastIndex = size - 1; 29202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int lastX = mXCoordinates.get(lastIndex); 29302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int lastY = mYCoordinates.get(lastIndex); 29402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int dist = getDistance(lastX, lastY, x, y); 29502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int msecs = time - mEventTimes.get(lastIndex); 29602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (msecs > 0) { 29702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int pixels = getDistance(lastX, lastY, x, y); 29802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int pixelsPerSec = pixels * MSEC_PER_SEC; 29958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (DEBUG_SPEED) { 30002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final float speed = (float)pixelsPerSec / msecs / mKeyWidth; 30158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format("[%d] detectFastMove: speed=%5.2f", mPointerId, speed)); 30202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 30302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka // Equivalent to (pixels / msecs < mStartSpeedThreshold / MSEC_PER_SEC) 3047a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka if (!hasDetectedFastMove() && pixelsPerSec > mDetectFastMoveSpeedThreshold * msecs) { 30502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (DEBUG) { 30658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final float speed = (float)pixelsPerSec / msecs / mKeyWidth; 30758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka Log.d(TAG, String.format( 30858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka "[%d] detectFastMove: speed=%5.2f T=%3d points=%3d fastMove", 30958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mPointerId, speed, time, size)); 31002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 31102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveTime = time; 31202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveX = x; 31302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka mDetectFastMoveY = y; 31402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 315f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 31602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return dist; 31702a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 31802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka 319b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka /** 320b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * Add a touch event as a gesture point. Returns true if the touch event is on the valid 321b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * gesture area. 322b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @param x the x-coordinate of the touch event 323b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @param y the y-coordinate of the touch event 324b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @param time the elapsed time in millisecond from the first gesture down 325b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @param isMajorEvent false if this is a historical move event 326b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka * @return true if the touch event is on the valid gesture area 327b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka */ 328b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public boolean addPointOnKeyboard(final int x, final int y, final int time, 329b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka final boolean isMajorEvent) { 330b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka final int size = getLength(); 33102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (size <= 0) { 33202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka // Down event 33302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka appendPoint(x, y, time); 33402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka updateMajorEvent(x, y, time); 33502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } else { 33658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final int distance = detectFastMove(x, y, time); 33758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (distance > mGestureSamplingMinimumDistance) { 33802a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka appendPoint(x, y, time); 33902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 340f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 34102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (isMajorEvent) { 34261dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka updateIncrementalRecognitionSize(x, y, time); 34302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka updateMajorEvent(x, y, time); 34461dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka } 345b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka return y >= mMinYCoordinate && y < mMaxYCoordinate; 34661dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka } 34761dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka 34861dcaaf17e4d1f9e941b961559a46823e6e25c99Tadashi G. Takaoka private void updateIncrementalRecognitionSize(final int x, final int y, final int time) { 34902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int msecs = (int)(time - mLastMajorEventTime); 35002a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (msecs <= 0) { 35102a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return; 35202a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka } 35302a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int pixels = getDistance(mLastMajorEventX, mLastMajorEventY, x, y); 35402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int pixelsPerSec = pixels * MSEC_PER_SEC; 35502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka // Equivalent to (pixels / msecs < mGestureRecognitionThreshold / MSEC_PER_SEC) 35602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka if (pixelsPerSec < mGestureRecognitionSpeedThreshold * msecs) { 357b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka mIncrementalRecognitionSize = getLength(); 358f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 35958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 36058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 36180bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka public final boolean hasRecognitionTimePast( 36258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final long currentTime, final long lastRecognitionTime) { 36380bcb9963259994cfb6497a19709198414aa860aTadashi G. Takaoka return currentTime > lastRecognitionTime + mParams.mRecognitionMinimumTime; 364f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 365f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 3667a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka public final void appendAllBatchPoints(final InputPointers out) { 367b2f5d1525093e66faa4a46d6cf10c0144fca2041Tadashi G. Takaoka appendBatchPoints(out, getLength()); 368f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 369f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 3707a17c1fcb52f0249108cfcbd789928320706718aTadashi G. Takaoka public final void appendIncrementalBatchPoints(final InputPointers out) { 3717519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka appendBatchPoints(out, mIncrementalRecognitionSize); 3727519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka } 3737519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka 3747519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka private void appendBatchPoints(final InputPointers out, final int size) { 3756c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka final int length = size - mLastIncrementalBatchSize; 3766c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka if (length <= 0) { 3776c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka return; 3786c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka } 3797519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka out.append(mPointerId, mEventTimes, mXCoordinates, mYCoordinates, 3806c3304ea961fd4da0a1da01dc1fac4797c713bccTadashi G. Takaoka mLastIncrementalBatchSize, length); 3817519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka mLastIncrementalBatchSize = size; 382f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 383f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka 38402a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka private static int getDistance(final int x1, final int y1, final int x2, final int y2) { 38502a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int dx = x1 - x2; 38602a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka final int dy = y1 - y2; 387bcec82de66f52655593dc233346f11468f5077a0Ken Wakasa // Note that, in recent versions of Android, FloatMath is actually slower than 388bcec82de66f52655593dc233346f11468f5077a0Ken Wakasa // java.lang.Math due to the way the JIT optimizes java.lang.Math. 38902a67200fc25d1be9dfbc35e3bb4b59bef28f386Tadashi G. Takaoka return (int)Math.sqrt(dx * dx + dy * dy); 390f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka } 391f39fccbd0fd63647c52e8eabcb60df69f97492b5Tadashi G. Takaoka} 392