Merge "Tweak beeline speed"

main
Satoshi Kataoka 2012-11-30 02:08:54 -08:00 committed by Android (Google) Code Review
commit 16e9d343c4
5 changed files with 99 additions and 30 deletions

View File

@ -86,7 +86,7 @@
<fraction name="config_gesture_sampling_minimum_distance">16.6666%</fraction> <fraction name="config_gesture_sampling_minimum_distance">16.6666%</fraction>
<!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) --> <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) -->
<integer name="config_gesture_recognition_minimum_time">100</integer> <integer name="config_gesture_recognition_minimum_time">100</integer>
<integer name="config_gesture_recognition_update_time">300</integer> <integer name="config_gesture_recognition_update_time">100</integer>
<fraction name="config_gesture_recognition_speed_threshold">550%</fraction> <fraction name="config_gesture_recognition_speed_threshold">550%</fraction>
<!-- Suppress showing key preview duration after batch input in millisecond --> <!-- Suppress showing key preview duration after batch input in millisecond -->
<integer name="config_suppress_key_preview_after_batch_input_duration">1000</integer> <integer name="config_suppress_key_preview_after_batch_input_duration">1000</integer>

View File

@ -16,6 +16,7 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
@ -42,6 +43,7 @@ public final class DebugSettings extends PreferenceFragment
private boolean mServiceNeedsRestart = false; private boolean mServiceNeedsRestart = false;
private CheckBoxPreference mDebugMode; private CheckBoxPreference mDebugMode;
private CheckBoxPreference mStatisticsLoggingPref;
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
@ -59,6 +61,7 @@ public final class DebugSettings extends PreferenceFragment
} }
final Preference statisticsLoggingPref = findPreference(PREF_STATISTICS_LOGGING_KEY); final Preference statisticsLoggingPref = findPreference(PREF_STATISTICS_LOGGING_KEY);
if (statisticsLoggingPref instanceof CheckBoxPreference) { if (statisticsLoggingPref instanceof CheckBoxPreference) {
mStatisticsLoggingPref = (CheckBoxPreference) statisticsLoggingPref;
if (!SHOW_STATISTICS_LOGGING) { if (!SHOW_STATISTICS_LOGGING) {
getPreferenceScreen().removePreference(statisticsLoggingPref); getPreferenceScreen().removePreference(statisticsLoggingPref);
} }
@ -80,6 +83,14 @@ public final class DebugSettings extends PreferenceFragment
if (key.equals(DEBUG_MODE_KEY)) { if (key.equals(DEBUG_MODE_KEY)) {
if (mDebugMode != null) { if (mDebugMode != null) {
mDebugMode.setChecked(prefs.getBoolean(DEBUG_MODE_KEY, false)); mDebugMode.setChecked(prefs.getBoolean(DEBUG_MODE_KEY, false));
final boolean checked = mDebugMode.isChecked();
if (mStatisticsLoggingPref != null) {
if (checked) {
getPreferenceScreen().addPreference(mStatisticsLoggingPref);
} else {
getPreferenceScreen().removePreference(mStatisticsLoggingPref);
}
}
updateDebugMode(); updateDebugMode();
mServiceNeedsRestart = true; mServiceNeedsRestart = true;
} }

View File

@ -429,4 +429,10 @@ typedef enum {
// Additional proximity char which can differ by language. // Additional proximity char which can differ by language.
ADDITIONAL_PROXIMITY_CHAR ADDITIONAL_PROXIMITY_CHAR
} ProximityType; } ProximityType;
typedef enum {
NOT_A_DOUBLE_LETTER,
A_DOUBLE_LETTER,
A_STRONG_DOUBLE_LETTER
} DoubleLetterLevel;
#endif // LATINIME_DEFINES_H #endif // LATINIME_DEFINES_H

View File

@ -31,6 +31,10 @@ const int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR =
1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
const float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f; const float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f;
const int ProximityInfoState::NOT_A_CODE = -1; const int ProximityInfoState::NOT_A_CODE = -1;
const int ProximityInfoState::LOOKUP_RADIUS_PERCENTILE = 50;
const int ProximityInfoState::FIRST_POINT_TIME_OFFSET_MILLIS = 150;
const int ProximityInfoState::STRONG_DOUBLE_LETTER_TIME_MILLIS = 600;
const int ProximityInfoState::MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE = 5;
void ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength, void ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength,
const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize, const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize,
@ -105,7 +109,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
mNearKeysVector.clear(); mNearKeysVector.clear();
mSearchKeysVector.clear(); mSearchKeysVector.clear();
mSpeedRates.clear(); mSpeedRates.clear();
mBeelineSpeedRates.clear(); mBeelineSpeedPercentiles.clear();
mCharProbabilities.clear(); mCharProbabilities.clear();
mDirections.clear(); mDirections.clear();
} }
@ -253,9 +257,9 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
AKLOGI("===== sampled points ====="); AKLOGI("===== sampled points =====");
for (int i = 0; i < mSampledInputSize; ++i) { for (int i = 0; i < mSampledInputSize; ++i) {
if (isGeometric) { if (isGeometric) {
AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %.4f", AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d",
i, mSampledInputXs[i], mSampledInputYs[i], mTimes[i], mSpeedRates[i], i, mSampledInputXs[i], mSampledInputYs[i], mTimes[i], mSpeedRates[i],
getBeelineSpeedRate(i)); getBeelineSpeedPercentile(i));
} }
sampledX << mSampledInputXs[i]; sampledX << mSampledInputXs[i];
sampledY << mSampledInputYs[i]; sampledY << mSampledInputYs[i];
@ -366,54 +370,65 @@ void ProximityInfoState::refreshSpeedRates(const int inputSize, const int *const
} }
} }
static const int MAX_PERCENTILE = 100;
void ProximityInfoState::refreshBeelineSpeedRates(const int inputSize, void ProximityInfoState::refreshBeelineSpeedRates(const int inputSize,
const int *const xCoordinates, const int *const yCoordinates, const int * times) { const int *const xCoordinates, const int *const yCoordinates, const int * times) {
mBeelineSpeedRates.resize(mSampledInputSize); if (DEBUG_SAMPLING_POINTS){
AKLOGI("--- refresh beeline speed rates");
}
mBeelineSpeedPercentiles.resize(mSampledInputSize);
for (int i = 0; i < mSampledInputSize; ++i) { for (int i = 0; i < mSampledInputSize; ++i) {
mBeelineSpeedRates[i] = calculateBeelineSpeedRate( mBeelineSpeedPercentiles[i] = static_cast<int>(calculateBeelineSpeedRate(
i, inputSize, xCoordinates, yCoordinates, times); i, inputSize, xCoordinates, yCoordinates, times) * MAX_PERCENTILE);
} }
} }
float ProximityInfoState::calculateBeelineSpeedRate( float ProximityInfoState::calculateBeelineSpeedRate(
const int id, const int inputSize, const int *const xCoordinates, const int id, const int inputSize, const int *const xCoordinates,
const int *const yCoordinates, const int * times) const { const int *const yCoordinates, const int * times) const {
static const int MAX_PERCENTILE = 100; if (mSampledInputSize <= 0 || mAverageSpeed < 0.001f) {
static const int LOOKUP_TIME_PERCENTILE = 30; if (DEBUG_SAMPLING_POINTS){
static const int LOOKUP_RADIUS_PERCENTILE = 50; AKLOGI("--- invalid state: cancel. size = %d, ave = %f",
if (mSampledInputSize <= 0 || mAverageSpeed < 0.1f) { mSampledInputSize, mAverageSpeed);
}
return 1.0f; return 1.0f;
} }
const int lookupRadius = const int lookupRadius =
mProximityInfo->getMostCommonKeyWidth() * LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE; mProximityInfo->getMostCommonKeyWidth() * LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE;
const int x0 = mSampledInputXs[id]; const int x0 = mSampledInputXs[id];
const int y0 = mSampledInputYs[id]; const int y0 = mSampledInputYs[id];
const int lookupTime = const int actualInputIndex = mInputIndice[id];
(mTimes.back() - mTimes.front()) * LOOKUP_TIME_PERCENTILE / MAX_PERCENTILE;
if (lookupTime <= 0) {
return 1.0f;
}
int tempTime = 0; int tempTime = 0;
int tempBeelineDistance = 0; int tempBeelineDistance = 0;
int start = mInputIndice[id]; int start = actualInputIndex;
// lookup forward // lookup forward
while (start > 0 && tempTime < lookupTime && tempBeelineDistance < lookupRadius) { while (start > 0 && tempBeelineDistance < lookupRadius) {
tempTime += times[start] - times[start - 1]; tempTime += times[start] - times[start - 1];
--start; --start;
tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]); tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]);
} }
// Exclusive unless this is an edge point
if (start > 0 && start < actualInputIndex) {
++start;
}
tempTime= 0; tempTime= 0;
tempBeelineDistance = 0; tempBeelineDistance = 0;
int end = mInputIndice[id]; int end = actualInputIndex;
// lookup backward // lookup backward
while (end < static_cast<int>(inputSize - 1) && tempTime < lookupTime while (end < (inputSize - 1) && tempBeelineDistance < lookupRadius) {
&& tempBeelineDistance < lookupRadius) {
tempTime += times[end + 1] - times[end]; tempTime += times[end + 1] - times[end];
++end; ++end;
tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]); tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[end], yCoordinates[end]);
}
// Exclusive unless this is an edge point
if (end > actualInputIndex && end < (inputSize - 1)) {
--end;
} }
if (start == end) { if (start >= end) {
if (DEBUG_DOUBLE_LETTER) {
AKLOGI("--- double letter: start == end %d", start);
}
return 1.0f; return 1.0f;
} }
@ -422,11 +437,33 @@ float ProximityInfoState::calculateBeelineSpeedRate(
const int x3 = xCoordinates[end]; const int x3 = xCoordinates[end];
const int y3 = yCoordinates[end]; const int y3 = yCoordinates[end];
const int beelineDistance = getDistanceInt(x2, y2, x3, y3); const int beelineDistance = getDistanceInt(x2, y2, x3, y3);
const int time = times[end] - times[start]; int adjustedStartTime = times[start];
if (start == 0 && actualInputIndex == 0 && inputSize > 1) {
adjustedStartTime += FIRST_POINT_TIME_OFFSET_MILLIS;
}
int adjustedEndTime = times[end];
if (end == (inputSize - 1) && inputSize > 1) {
adjustedEndTime -= FIRST_POINT_TIME_OFFSET_MILLIS;
}
const int time = adjustedEndTime - adjustedStartTime;
if (time <= 0) { if (time <= 0) {
return 1.0f; return 1.0f;
} }
return (static_cast<float>(beelineDistance) / static_cast<float>(time)) / mAverageSpeed;
if (time >= STRONG_DOUBLE_LETTER_TIME_MILLIS){
return 0.0f;
}
if (DEBUG_DOUBLE_LETTER) {
AKLOGI("--- (%d, %d) double letter: start = %d, end = %d, dist = %d, time = %d, speed = %f,"
" ave = %f, val = %f, start time = %d, end time = %d",
id, mInputIndice[id], start, end, beelineDistance, time,
(static_cast<float>(beelineDistance) / static_cast<float>(time)), mAverageSpeed,
((static_cast<float>(beelineDistance) / static_cast<float>(time)) / mAverageSpeed),
adjustedStartTime, adjustedEndTime);
}
// Offset 1%
// TODO: Detect double letter more smartly
return 0.01f + static_cast<float>(beelineDistance) / static_cast<float>(time) / mAverageSpeed;
} }
bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize, bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize,

View File

@ -39,6 +39,10 @@ class ProximityInfoState {
static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR;
static const float NOT_A_DISTANCE_FLOAT; static const float NOT_A_DISTANCE_FLOAT;
static const int NOT_A_CODE; static const int NOT_A_CODE;
static const int LOOKUP_RADIUS_PERCENTILE;
static const int FIRST_POINT_TIME_OFFSET_MILLIS;
static const int STRONG_DOUBLE_LETTER_TIME_MILLIS;
static const int MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE;
///////////////////////////////////////// /////////////////////////////////////////
// Defined in proximity_info_state.cpp // // Defined in proximity_info_state.cpp //
@ -56,8 +60,8 @@ class ProximityInfoState {
mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mLocaleStr(), mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mLocaleStr(),
mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0), mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0),
mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mTimes(), mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mTimes(),
mInputIndice(), mLengthCache(), mDistanceCache(), mSpeedRates(), mInputIndice(), mLengthCache(), mBeelineSpeedPercentiles(), mDistanceCache(),
mDirections(), mBeelineSpeedRates(), mCharProbabilities(), mNearKeysVector(), mSpeedRates(), mDirections(), mCharProbabilities(), mNearKeysVector(),
mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) { mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) {
memset(mInputCodes, 0, sizeof(mInputCodes)); memset(mInputCodes, 0, sizeof(mInputCodes));
memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances)); memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances));
@ -167,8 +171,19 @@ class ProximityInfoState {
return mSpeedRates[index]; return mSpeedRates[index];
} }
AK_FORCE_INLINE float getBeelineSpeedRate(const int id) const { AK_FORCE_INLINE int getBeelineSpeedPercentile(const int id) const {
return mBeelineSpeedRates[id]; return mBeelineSpeedPercentiles[id];
}
AK_FORCE_INLINE DoubleLetterLevel getDoubleLetterLevel(const int id) const {
const int beelineSpeedRate = getBeelineSpeedPercentile(id);
if (beelineSpeedRate == 0) {
return A_STRONG_DOUBLE_LETTER;
} else if (beelineSpeedRate < MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE) {
return A_DOUBLE_LETTER;
} else {
return NOT_A_DOUBLE_LETTER;
}
} }
float getDirection(const int index) const { float getDirection(const int index) const {
@ -259,10 +274,10 @@ class ProximityInfoState {
std::vector<int> mTimes; std::vector<int> mTimes;
std::vector<int> mInputIndice; std::vector<int> mInputIndice;
std::vector<int> mLengthCache; std::vector<int> mLengthCache;
std::vector<int> mBeelineSpeedPercentiles;
std::vector<float> mDistanceCache; std::vector<float> mDistanceCache;
std::vector<float> mSpeedRates; std::vector<float> mSpeedRates;
std::vector<float> mDirections; std::vector<float> mDirections;
std::vector<float> mBeelineSpeedRates;
// probabilities of skipping or mapping to a key for each point. // probabilities of skipping or mapping to a key for each point.
std::vector<hash_map_compat<int, float> > mCharProbabilities; std::vector<hash_map_compat<int, float> > mCharProbabilities;
// The vector for the key code set which holds nearby keys for each sampled input point // The vector for the key code set which holds nearby keys for each sampled input point