Merge "Separate BogusMoveEventDetector class"
commit
db6d9b0ab4
|
@ -19,11 +19,11 @@ package com.android.inputmethod.keyboard;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
import com.android.inputmethod.accessibility.AccessibilityUtils;
|
import com.android.inputmethod.accessibility.AccessibilityUtils;
|
||||||
|
import com.android.inputmethod.keyboard.internal.BogusMoveEventDetector;
|
||||||
import com.android.inputmethod.keyboard.internal.GestureStroke;
|
import com.android.inputmethod.keyboard.internal.GestureStroke;
|
||||||
import com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams;
|
import com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams;
|
||||||
import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints;
|
import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints;
|
||||||
|
@ -145,9 +145,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
// Move this threshold to resource.
|
// Move this threshold to resource.
|
||||||
// TODO: Device specific parameter would be better for device specific hack?
|
// TODO: Device specific parameter would be better for device specific hack?
|
||||||
private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth
|
private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth
|
||||||
// This hack is applied to certain classes of tablets.
|
|
||||||
// See {@link #needsProximateBogusDownMoveUpEventHack(Resources)}.
|
|
||||||
private static boolean sNeedsProximateBogusDownMoveUpEventHack;
|
|
||||||
|
|
||||||
private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList();
|
private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList();
|
||||||
private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue();
|
private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue();
|
||||||
|
@ -174,57 +171,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
private static int sLastRecognitionPointSize = 0; // synchronized using sAggregatedPointers
|
private static int sLastRecognitionPointSize = 0; // synchronized using sAggregatedPointers
|
||||||
private static long sLastRecognitionTime = 0; // synchronized using sAggregatedPointers
|
private static long sLastRecognitionTime = 0; // synchronized using sAggregatedPointers
|
||||||
|
|
||||||
static final class BogusMoveEventDetector {
|
|
||||||
// Move these thresholds to resource.
|
|
||||||
// These thresholds' unit is a diagonal length of a key.
|
|
||||||
private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f;
|
|
||||||
private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f;
|
|
||||||
|
|
||||||
private int mAccumulatedDistanceThreshold;
|
|
||||||
private int mRadiusThreshold;
|
|
||||||
|
|
||||||
// Accumulated distance from actual and artificial down keys.
|
|
||||||
/* package */ int mAccumulatedDistanceFromDownKey;
|
|
||||||
private int mActualDownX;
|
|
||||||
private int mActualDownY;
|
|
||||||
|
|
||||||
public void setKeyboardGeometry(final int keyWidth, final int keyHeight) {
|
|
||||||
final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight);
|
|
||||||
mAccumulatedDistanceThreshold = (int)(
|
|
||||||
keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD);
|
|
||||||
mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onActualDownEvent(final int x, final int y) {
|
|
||||||
mActualDownX = x;
|
|
||||||
mActualDownY = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDownKey() {
|
|
||||||
mAccumulatedDistanceFromDownKey = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onMoveKey(final int distance) {
|
|
||||||
mAccumulatedDistanceFromDownKey += distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasTraveledLongDistance(final int x, final int y) {
|
|
||||||
final int dx = Math.abs(x - mActualDownX);
|
|
||||||
final int dy = Math.abs(y - mActualDownY);
|
|
||||||
// A bogus move event should be a horizontal movement. A vertical movement might be
|
|
||||||
// a sloppy typing and should be ignored.
|
|
||||||
return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ int getDistanceFromDownEvent(final int x, final int y) {
|
|
||||||
return getDistance(x, y, mActualDownX, mActualDownY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCloseToActualDownEvent(final int x, final int y) {
|
|
||||||
return getDistanceFromDownEvent(x, y) < mRadiusThreshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The position and time at which first down event occurred.
|
// The position and time at which first down event occurred.
|
||||||
private long mDownTime;
|
private long mDownTime;
|
||||||
private int[] mDownCoordinates = CoordinateUtils.newInstance();
|
private int[] mDownCoordinates = CoordinateUtils.newInstance();
|
||||||
|
@ -263,29 +209,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
|
|
||||||
private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints;
|
private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints;
|
||||||
|
|
||||||
private static final int SMALL_TABLET_SMALLEST_WIDTH = 600; // dp
|
|
||||||
private static final int LARGE_TABLET_SMALLEST_WIDTH = 768; // dp
|
|
||||||
|
|
||||||
private static boolean needsProximateBogusDownMoveUpEventHack(final Resources res) {
|
|
||||||
// The proximate bogus down move up event hack is needed for a device such like,
|
|
||||||
// 1) is large tablet, or 2) is small tablet and the screen density is less than hdpi.
|
|
||||||
// Though it seems odd to use screen density as criteria of the quality of the touch
|
|
||||||
// screen, the small table that has a less density screen than hdpi most likely has been
|
|
||||||
// made with the touch screen that needs the hack.
|
|
||||||
final int sw = res.getConfiguration().smallestScreenWidthDp;
|
|
||||||
final boolean isLargeTablet = (sw >= LARGE_TABLET_SMALLEST_WIDTH);
|
|
||||||
final boolean isSmallTablet =
|
|
||||||
(sw >= SMALL_TABLET_SMALLEST_WIDTH && sw < LARGE_TABLET_SMALLEST_WIDTH);
|
|
||||||
final int densityDpi = res.getDisplayMetrics().densityDpi;
|
|
||||||
final boolean hasLowDensityScreen = (densityDpi < DisplayMetrics.DENSITY_HIGH);
|
|
||||||
final boolean needsTheHack = isLargeTablet || (isSmallTablet && hasLowDensityScreen);
|
|
||||||
if (DEBUG_MODE) {
|
|
||||||
Log.d(TAG, "needsProximateBogusDownMoveUpEventHack=" + needsTheHack
|
|
||||||
+ " smallestScreenWidthDp=" + sw + " densityDpi=" + densityDpi);
|
|
||||||
}
|
|
||||||
return needsTheHack;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add PointerTrackerFactory singleton and move some class static methods into it.
|
// TODO: Add PointerTrackerFactory singleton and move some class static methods into it.
|
||||||
public static void init(final TypedArray mainKeyboardViewAttr, final TimerProxy timerProxy,
|
public static void init(final TypedArray mainKeyboardViewAttr, final TimerProxy timerProxy,
|
||||||
final DrawingProxy drawingProxy) {
|
final DrawingProxy drawingProxy) {
|
||||||
|
@ -300,7 +223,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
sNeedsPhantomSuddenMoveEventHack = Boolean.parseBoolean(
|
sNeedsPhantomSuddenMoveEventHack = Boolean.parseBoolean(
|
||||||
ResourceUtils.getDeviceOverrideValue(
|
ResourceUtils.getDeviceOverrideValue(
|
||||||
res, R.array.phantom_sudden_move_event_device_list));
|
res, R.array.phantom_sudden_move_event_device_list));
|
||||||
sNeedsProximateBogusDownMoveUpEventHack = needsProximateBogusDownMoveUpEventHack(res);
|
BogusMoveEventDetector.init(res);
|
||||||
|
|
||||||
sTimerProxy = timerProxy;
|
sTimerProxy = timerProxy;
|
||||||
sDrawingProxy = drawingProxy;
|
sDrawingProxy = drawingProxy;
|
||||||
|
@ -637,7 +560,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
return onMoveToNewKey(onMoveKeyInternal(x, y), x, y);
|
return onMoveToNewKey(onMoveKeyInternal(x, y), x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getDistance(final int x1, final int y1, final int x2, final int y2) {
|
private static int getDistance(final int x1, final int y1, final int x2, final int y2) {
|
||||||
return (int)Math.hypot(x1 - x2, y1 - y2);
|
return (int)Math.hypot(x1 - x2, y1 - y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1047,8 +970,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
// HACK: On some devices, quick successive proximate touches may be reported as a bogus
|
// HACK: On some devices, quick successive proximate touches may be reported as a bogus
|
||||||
// down-move-up event by touch panel firmware. This hack detects such cases and breaks
|
// down-move-up event by touch panel firmware. This hack detects such cases and breaks
|
||||||
// these events into separate up and down events.
|
// these events into separate up and down events.
|
||||||
else if (sNeedsProximateBogusDownMoveUpEventHack
|
else if (sTypingTimeRecorder.isInFastTyping(eventTime)
|
||||||
&& sTypingTimeRecorder.isInFastTyping(eventTime)
|
|
||||||
&& mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) {
|
&& mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) {
|
||||||
processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY);
|
processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY);
|
||||||
}
|
}
|
||||||
|
@ -1265,14 +1187,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedDraggingFinger
|
if (!mIsAllowedDraggingFinger && sTypingTimeRecorder.isInFastTyping(eventTime)
|
||||||
&& sTypingTimeRecorder.isInFastTyping(eventTime)
|
|
||||||
&& mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) {
|
&& mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) {
|
||||||
if (DEBUG_MODE) {
|
if (DEBUG_MODE) {
|
||||||
final float keyDiagonal = (float)Math.hypot(
|
final float keyDiagonal = (float)Math.hypot(
|
||||||
mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
|
mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
|
||||||
final float lengthFromDownRatio =
|
final float lengthFromDownRatio =
|
||||||
mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal;
|
mBogusMoveEventDetector.getAccumulatedDistanceFromDownKey() / keyDiagonal;
|
||||||
Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:"
|
Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:"
|
||||||
+ " %.2f key diagonal from virtual down point",
|
+ " %.2f key diagonal from virtual down point",
|
||||||
mPointerId, lengthFromDownRatio));
|
mPointerId, lengthFromDownRatio));
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.inputmethod.keyboard.internal;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
|
|
||||||
|
// This hack is applied to certain classes of tablets.
|
||||||
|
public final class BogusMoveEventDetector {
|
||||||
|
private static final String TAG = BogusMoveEventDetector.class.getSimpleName();
|
||||||
|
private static final boolean DEBUG_MODE = LatinImeLogger.sDBG;
|
||||||
|
|
||||||
|
// Move these thresholds to resource.
|
||||||
|
// These thresholds' unit is a diagonal length of a key.
|
||||||
|
private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f;
|
||||||
|
private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f;
|
||||||
|
|
||||||
|
private static final int SMALL_TABLET_SMALLEST_WIDTH = 600; // dp
|
||||||
|
private static final int LARGE_TABLET_SMALLEST_WIDTH = 768; // dp
|
||||||
|
|
||||||
|
private static boolean sNeedsProximateBogusDownMoveUpEventHack;
|
||||||
|
|
||||||
|
public static void init(final Resources res) {
|
||||||
|
// The proximate bogus down move up event hack is needed for a device such like,
|
||||||
|
// 1) is large tablet, or 2) is small tablet and the screen density is less than hdpi.
|
||||||
|
// Though it seems odd to use screen density as criteria of the quality of the touch
|
||||||
|
// screen, the small table that has a less density screen than hdpi most likely has been
|
||||||
|
// made with the touch screen that needs the hack.
|
||||||
|
final int sw = res.getConfiguration().smallestScreenWidthDp;
|
||||||
|
final boolean isLargeTablet = (sw >= LARGE_TABLET_SMALLEST_WIDTH);
|
||||||
|
final boolean isSmallTablet =
|
||||||
|
(sw >= SMALL_TABLET_SMALLEST_WIDTH && sw < LARGE_TABLET_SMALLEST_WIDTH);
|
||||||
|
final int densityDpi = res.getDisplayMetrics().densityDpi;
|
||||||
|
final boolean hasLowDensityScreen = (densityDpi < DisplayMetrics.DENSITY_HIGH);
|
||||||
|
final boolean needsTheHack = isLargeTablet || (isSmallTablet && hasLowDensityScreen);
|
||||||
|
if (DEBUG_MODE) {
|
||||||
|
Log.d(TAG, "needsProximateBogusDownMoveUpEventHack=" + needsTheHack
|
||||||
|
+ " smallestScreenWidthDp=" + sw + " densityDpi=" + densityDpi);
|
||||||
|
}
|
||||||
|
sNeedsProximateBogusDownMoveUpEventHack = needsTheHack;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int mAccumulatedDistanceThreshold;
|
||||||
|
private int mRadiusThreshold;
|
||||||
|
|
||||||
|
// Accumulated distance from actual and artificial down keys.
|
||||||
|
/* package */ int mAccumulatedDistanceFromDownKey;
|
||||||
|
private int mActualDownX;
|
||||||
|
private int mActualDownY;
|
||||||
|
|
||||||
|
public void setKeyboardGeometry(final int keyWidth, final int keyHeight) {
|
||||||
|
final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight);
|
||||||
|
mAccumulatedDistanceThreshold = (int)(
|
||||||
|
keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD);
|
||||||
|
mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onActualDownEvent(final int x, final int y) {
|
||||||
|
mActualDownX = x;
|
||||||
|
mActualDownY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDownKey() {
|
||||||
|
mAccumulatedDistanceFromDownKey = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onMoveKey(final int distance) {
|
||||||
|
mAccumulatedDistanceFromDownKey += distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasTraveledLongDistance(final int x, final int y) {
|
||||||
|
if (!sNeedsProximateBogusDownMoveUpEventHack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final int dx = Math.abs(x - mActualDownX);
|
||||||
|
final int dy = Math.abs(y - mActualDownY);
|
||||||
|
// A bogus move event should be a horizontal movement. A vertical movement might be
|
||||||
|
// a sloppy typing and should be ignored.
|
||||||
|
return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAccumulatedDistanceFromDownKey() {
|
||||||
|
return mAccumulatedDistanceFromDownKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDistanceFromDownEvent(final int x, final int y) {
|
||||||
|
return getDistance(x, y, mActualDownX, mActualDownY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getDistance(final int x1, final int y1, final int x2, final int y2) {
|
||||||
|
return (int)Math.hypot(x1 - x2, y1 - y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCloseToActualDownEvent(final int x, final int y) {
|
||||||
|
return sNeedsProximateBogusDownMoveUpEventHack
|
||||||
|
&& getDistanceFromDownEvent(x, y) < mRadiusThreshold;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue