diff options
-rw-r--r-- | java/res/values/config.xml | 2 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/keyboard/PointerTracker.java | 2 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/DebugSettings.java | 11 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/LatinIME.java | 7 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/research/MainLogBuffer.java | 11 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/research/ResearchLogger.java | 10 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/research/Statistics.java | 8 | ||||
-rw-r--r-- | native/jni/src/binary_format.h | 2 | ||||
-rw-r--r-- | native/jni/src/defines.h | 6 | ||||
-rw-r--r-- | native/jni/src/proximity_info_state.cpp | 85 | ||||
-rw-r--r-- | native/jni/src/proximity_info_state.h | 25 |
11 files changed, 130 insertions, 39 deletions
diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 78c5f1834..8d947b327 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -86,7 +86,7 @@ <fraction name="config_gesture_sampling_minimum_distance">16.6666%</fraction> <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) --> <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> <!-- Suppress showing key preview duration after batch input in millisecond --> <integer name="config_suppress_key_preview_after_batch_input_duration">1000</integer> diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 296a45faf..c3cf49f3b 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -749,12 +749,12 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (getActivePointerTrackerCount() == 1) { sInGesture = false; sTimeRecorder.onEndBatchInput(eventTime); + mTimerProxy.cancelAllUpdateBatchInputTimers(); if (!mIsTrackingCanceled) { if (DEBUG_LISTENER) { Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", mPointerId, sAggregratedPointers.getPointerSize())); } - mTimerProxy.cancelAllUpdateBatchInputTimers(); mListener.onEndBatchInput(sAggregratedPointers); } } diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java index 731b9baf5..989451b1c 100644 --- a/java/src/com/android/inputmethod/latin/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/DebugSettings.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; +import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageInfo; @@ -42,6 +43,7 @@ public final class DebugSettings extends PreferenceFragment private boolean mServiceNeedsRestart = false; private CheckBoxPreference mDebugMode; + private CheckBoxPreference mStatisticsLoggingPref; @Override public void onCreate(Bundle icicle) { @@ -59,6 +61,7 @@ public final class DebugSettings extends PreferenceFragment } final Preference statisticsLoggingPref = findPreference(PREF_STATISTICS_LOGGING_KEY); if (statisticsLoggingPref instanceof CheckBoxPreference) { + mStatisticsLoggingPref = (CheckBoxPreference) statisticsLoggingPref; if (!SHOW_STATISTICS_LOGGING) { getPreferenceScreen().removePreference(statisticsLoggingPref); } @@ -80,6 +83,14 @@ public final class DebugSettings extends PreferenceFragment if (key.equals(DEBUG_MODE_KEY)) { if (mDebugMode != null) { 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(); mServiceNeedsRestart = true; } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 0b49659e3..8519ad31d 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1464,7 +1464,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private static final class BatchInputUpdater implements Handler.Callback { private final Handler mHandler; private LatinIME mLatinIme; - private boolean mInBatchInput; // synchornized using "this". + private boolean mInBatchInput; // synchronized using "this". private BatchInputUpdater() { final HandlerThread handlerThread = new HandlerThread( @@ -1496,6 +1496,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // Run in the UI thread. public synchronized void onStartBatchInput() { + mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); mInBatchInput = true; } @@ -1503,7 +1504,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private synchronized void updateBatchInput(final InputPointers batchPointers, final LatinIME latinIme) { if (!mInBatchInput) { - // Batch input has ended while the message was being delivered. + // Batch input has ended or canceled while the message was being delivered. return; } final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked( @@ -1523,7 +1524,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction .sendToTarget(); } - public void onCancelBatchInput(final LatinIME latinIme) { + public synchronized void onCancelBatchInput(final LatinIME latinIme) { mInBatchInput = false; latinIme.mHandler.showGesturePreviewAndSuggestionStrip( SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java index 745768d35..94dbf3960 100644 --- a/java/src/com/android/inputmethod/research/MainLogBuffer.java +++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java @@ -16,16 +16,22 @@ package com.android.inputmethod.research; +import android.util.Log; + import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.Suggest; import java.util.Random; public class MainLogBuffer extends LogBuffer { + private static final String TAG = MainLogBuffer.class.getSimpleName(); + // For privacy reasons, be sure to set to "false" for production code. + private static final boolean DEBUG = false; + // The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams. private static final int N_GRAM_SIZE = 2; // The number of words between n-grams to omit from the log. - private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES = 18; + private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES = DEBUG ? 2 : 18; private final ResearchLog mResearchLog; private Suggest mSuggest; @@ -61,6 +67,9 @@ public class MainLogBuffer extends LogBuffer { mWordsUntilSafeToSample--; } } + if (DEBUG) { + Log.d(TAG, "shiftedIn " + (newLogUnit.hasWord() ? newLogUnit.getWord() : "")); + } } public void resetWordCounter() { diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index ea3f6fd7a..fe31039e3 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -60,6 +60,7 @@ import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.latin.CollectionUtils; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.InputTypeUtils; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputConnection; @@ -687,7 +688,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /* package for test */ void commitCurrentLogUnit() { if (DEBUG) { - Log.d(TAG, "commitCurrentLogUnit"); + Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ? + ": " + mCurrentLogUnit.getWord() : "")); } if (!mCurrentLogUnit.isEmpty()) { if (mMainLogBuffer != null) { @@ -808,8 +810,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo, final SharedPreferences prefs) { final ResearchLogger researchLogger = getInstance(); - researchLogger.start(); if (editorInfo != null) { + final boolean isPassword = InputTypeUtils.isPasswordInputType(editorInfo.inputType) + || InputTypeUtils.isVisiblePasswordInputType(editorInfo.inputType); + getInstance().setIsPasswordView(isPassword); + researchLogger.start(); final Context context = researchLogger.mInputMethodService; try { final PackageInfo packageInfo; @@ -1076,7 +1081,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang keyboard.mOccupiedHeight, keyboard.mKeys }; - getInstance().setIsPasswordView(isPasswordView); getInstance().enqueueEvent(EVENTKEYS_MAINKEYBOARDVIEW_SETKEYBOARD, values); } } diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java index 98491bd23..2065ab15e 100644 --- a/java/src/com/android/inputmethod/research/Statistics.java +++ b/java/src/com/android/inputmethod/research/Statistics.java @@ -16,9 +16,14 @@ package com.android.inputmethod.research; +import android.util.Log; + import com.android.inputmethod.latin.Constants; public class Statistics { + private static final String TAG = Statistics.class.getSimpleName(); + private static final boolean DEBUG = false; + // Number of characters entered during a typing session int mCharCount; // Number of letter characters entered during a typing session @@ -103,6 +108,9 @@ public class Statistics { } public void recordChar(int codePoint, long time) { + if (DEBUG) { + Log.d(TAG, "recordChar() called"); + } final long delta = time - mLastTapTime; if (codePoint == Constants.CODE_DELETE) { mDeleteKeyCount++; diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h index 86410fb8f..d1e8316de 100644 --- a/native/jni/src/binary_format.h +++ b/native/jni/src/binary_format.h @@ -17,7 +17,7 @@ #ifndef LATINIME_BINARY_FORMAT_H #define LATINIME_BINARY_FORMAT_H -#include <cctype> +#include <cstdlib> #include <limits> #include <map> #include "bloom_filter.h" diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index c504cecf9..38090275f 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -429,4 +429,10 @@ typedef enum { // Additional proximity char which can differ by language. ADDITIONAL_PROXIMITY_CHAR } ProximityType; + +typedef enum { + NOT_A_DOUBLE_LETTER, + A_DOUBLE_LETTER, + A_STRONG_DOUBLE_LETTER +} DoubleLetterLevel; #endif // LATINIME_DEFINES_H diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp index 740e1a24e..a1e20cfeb 100644 --- a/native/jni/src/proximity_info_state.cpp +++ b/native/jni/src/proximity_info_state.cpp @@ -31,6 +31,10 @@ const int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; const float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f; 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, 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(); mSearchKeysVector.clear(); mSpeedRates.clear(); - mBeelineSpeedRates.clear(); + mBeelineSpeedPercentiles.clear(); mCharProbabilities.clear(); mDirections.clear(); } @@ -253,9 +257,9 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi AKLOGI("===== sampled points ====="); for (int i = 0; i < mSampledInputSize; ++i) { 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], - getBeelineSpeedRate(i)); + getBeelineSpeedPercentile(i)); } sampledX << mSampledInputXs[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, 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) { - mBeelineSpeedRates[i] = calculateBeelineSpeedRate( - i, inputSize, xCoordinates, yCoordinates, times); + mBeelineSpeedPercentiles[i] = static_cast<int>(calculateBeelineSpeedRate( + i, inputSize, xCoordinates, yCoordinates, times) * MAX_PERCENTILE); } } float ProximityInfoState::calculateBeelineSpeedRate( const int id, const int inputSize, const int *const xCoordinates, const int *const yCoordinates, const int * times) const { - static const int MAX_PERCENTILE = 100; - static const int LOOKUP_TIME_PERCENTILE = 30; - static const int LOOKUP_RADIUS_PERCENTILE = 50; - if (mSampledInputSize <= 0 || mAverageSpeed < 0.1f) { + if (mSampledInputSize <= 0 || mAverageSpeed < 0.001f) { + if (DEBUG_SAMPLING_POINTS){ + AKLOGI("--- invalid state: cancel. size = %d, ave = %f", + mSampledInputSize, mAverageSpeed); + } return 1.0f; } const int lookupRadius = mProximityInfo->getMostCommonKeyWidth() * LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE; const int x0 = mSampledInputXs[id]; const int y0 = mSampledInputYs[id]; - const int lookupTime = - (mTimes.back() - mTimes.front()) * LOOKUP_TIME_PERCENTILE / MAX_PERCENTILE; - if (lookupTime <= 0) { - return 1.0f; - } + const int actualInputIndex = mInputIndice[id]; int tempTime = 0; int tempBeelineDistance = 0; - int start = mInputIndice[id]; + int start = actualInputIndex; // lookup forward - while (start > 0 && tempTime < lookupTime && tempBeelineDistance < lookupRadius) { + while (start > 0 && tempBeelineDistance < lookupRadius) { tempTime += times[start] - times[start - 1]; --start; tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]); } + // Exclusive unless this is an edge point + if (start > 0 && start < actualInputIndex) { + ++start; + } tempTime= 0; tempBeelineDistance = 0; - int end = mInputIndice[id]; + int end = actualInputIndex; // lookup backward - while (end < static_cast<int>(inputSize - 1) && tempTime < lookupTime - && tempBeelineDistance < lookupRadius) { + while (end < (inputSize - 1) && tempBeelineDistance < lookupRadius) { tempTime += times[end + 1] - times[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; } @@ -422,11 +437,33 @@ float ProximityInfoState::calculateBeelineSpeedRate( const int x3 = xCoordinates[end]; const int y3 = yCoordinates[end]; 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) { 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, diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h index 97281af1c..5f968e17a 100644 --- a/native/jni/src/proximity_info_state.h +++ b/native/jni/src/proximity_info_state.h @@ -39,6 +39,10 @@ class ProximityInfoState { static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; static const float NOT_A_DISTANCE_FLOAT; 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 // @@ -56,8 +60,8 @@ class ProximityInfoState { mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mLocaleStr(), mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0), mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mTimes(), - mInputIndice(), mLengthCache(), mDistanceCache(), mSpeedRates(), - mDirections(), mBeelineSpeedRates(), mCharProbabilities(), mNearKeysVector(), + mInputIndice(), mLengthCache(), mBeelineSpeedPercentiles(), mDistanceCache(), + mSpeedRates(), mDirections(), mCharProbabilities(), mNearKeysVector(), mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) { memset(mInputCodes, 0, sizeof(mInputCodes)); memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances)); @@ -167,8 +171,19 @@ class ProximityInfoState { return mSpeedRates[index]; } - AK_FORCE_INLINE float getBeelineSpeedRate(const int id) const { - return mBeelineSpeedRates[id]; + AK_FORCE_INLINE int getBeelineSpeedPercentile(const int id) const { + 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 { @@ -259,10 +274,10 @@ class ProximityInfoState { std::vector<int> mTimes; std::vector<int> mInputIndice; std::vector<int> mLengthCache; + std::vector<int> mBeelineSpeedPercentiles; std::vector<float> mDistanceCache; std::vector<float> mSpeedRates; std::vector<float> mDirections; - std::vector<float> mBeelineSpeedRates; // probabilities of skipping or mapping to a key for each point. std::vector<hash_map_compat<int, float> > mCharProbabilities; // The vector for the key code set which holds nearby keys for each sampled input point |