LatinIME/java/src/com/android/inputmethod/keyboard/internal/BogusMoveEventDetector.java

116 lines
4.8 KiB
Java

/*
* 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.R;
import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.define.DebugFlags;
// 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 = DebugFlags.DEBUG_ENABLED;
// 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 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 screenMetrics = res.getInteger(R.integer.config_screen_metrics);
final boolean isLargeTablet = (screenMetrics == Constants.SCREEN_METRICS_LARGE_TABLET);
final boolean isSmallTablet = (screenMetrics == Constants.SCREEN_METRICS_SMALL_TABLET);
final int densityDpi = res.getDisplayMetrics().densityDpi;
final boolean hasLowDensityScreen = (densityDpi < DisplayMetrics.DENSITY_HIGH);
final boolean needsTheHack = isLargeTablet || (isSmallTablet && hasLowDensityScreen);
if (DEBUG_MODE) {
final int sw = res.getConfiguration().smallestScreenWidthDp;
Log.d(TAG, "needsProximateBogusDownMoveUpEventHack=" + needsTheHack
+ " smallestScreenWidthDp=" + sw + " densityDpi=" + densityDpi
+ " screenMetrics=" + screenMetrics);
}
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;
}
}