aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/values/config.xml2
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java2
-rw-r--r--java/src/com/android/inputmethod/latin/DebugSettings.java11
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java7
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java11
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java10
-rw-r--r--java/src/com/android/inputmethod/research/Statistics.java8
-rw-r--r--native/jni/src/binary_format.h2
-rw-r--r--native/jni/src/defines.h6
-rw-r--r--native/jni/src/proximity_info_state.cpp85
-rw-r--r--native/jni/src/proximity_info_state.h25
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 61b88b30d..390c60cd7 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;
@@ -689,7 +690,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
/* package for test */ void commitCurrentLogUnit(final long maxTime) {
if (DEBUG) {
- Log.d(TAG, "commitCurrentLogUnit");
+ Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ?
+ ": " + mCurrentLogUnit.getWord() : ""));
}
if (!mCurrentLogUnit.isEmpty()) {
final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime);
@@ -811,8 +813,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;
@@ -1079,7 +1084,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