aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/values-fr/donottranslate.xml18
-rw-r--r--java/res/values/donottranslate.xml19
-rw-r--r--java/res/values/strings.xml3
-rw-r--r--java/res/xml/key_styles_common.xml2
-rw-r--r--java/res/xml/key_styles_enter.xml22
-rw-r--r--java/res/xml/spellchecker.xml12
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java7
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java26
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java22
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java36
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java7
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java56
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java4
-rw-r--r--java/src/com/android/inputmethod/latin/DicTraverseSession.java6
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java14
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java5
-rw-r--r--java/src/com/android/inputmethod/latin/InputTypeUtils.java7
-rw-r--r--java/src/com/android/inputmethod/latin/LastComposedWord.java9
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java162
-rw-r--r--java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java4
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java13
-rw-r--r--java/src/com/android/inputmethod/latin/SeekBarDialog.java36
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java16
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsFragment.java58
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java68
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java5
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java3
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java20
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java11
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java266
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java9
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java12
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java136
-rw-r--r--java/src/com/android/inputmethod/research/Statistics.java56
-rw-r--r--native/jni/Android.mk4
-rw-r--r--native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp14
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp58
-rw-r--r--native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp6
-rw-r--r--native/jni/src/bigram_dictionary.cpp83
-rw-r--r--native/jni/src/bigram_dictionary.h17
-rw-r--r--native/jni/src/correction.cpp31
-rw-r--r--native/jni/src/correction.h12
-rw-r--r--native/jni/src/defines.h43
-rw-r--r--native/jni/src/dictionary.cpp45
-rw-r--r--native/jni/src/dictionary.h9
-rw-r--r--native/jni/src/geometry_utils.h15
-rw-r--r--native/jni/src/proximity_info.cpp2
-rw-r--r--native/jni/src/proximity_info_state.cpp17
-rw-r--r--native/jni/src/proximity_info_state.h13
-rw-r--r--native/jni/src/suggest/gesture_suggest.cpp2
-rw-r--r--native/jni/src/suggest/gesture_suggest.h22
-rw-r--r--native/jni/src/suggest/suggest_interface.h5
-rw-r--r--native/jni/src/suggest/typing_suggest.cpp2
-rw-r--r--native/jni/src/suggest/typing_suggest.h22
-rw-r--r--native/jni/src/suggest_utils.h57
-rw-r--r--native/jni/src/terminal_attributes.h11
-rw-r--r--native/jni/src/unigram_dictionary.cpp71
-rw-r--r--native/jni/src/unigram_dictionary.h13
-rw-r--r--native/jni/src/words_priority_queue.h15
-rw-r--r--native/jni/src/words_priority_queue_pool.h7
-rw-r--r--tools/maketext/res/values-ar/donottranslate-more-keys.xml3
-rw-r--r--tools/maketext/res/values-fa/donottranslate-more-keys.xml3
-rw-r--r--tools/maketext/src/com/android/inputmethod/latin/maketext/StringResourceMap.java4
66 files changed, 1082 insertions, 682 deletions
diff --git a/java/res/values-fr/donottranslate.xml b/java/res/values-fr/donottranslate.xml
index e11e65c79..2e916a734 100644
--- a/java/res/values-fr/donottranslate.xml
+++ b/java/res/values-fr/donottranslate.xml
@@ -18,15 +18,13 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Symbols that should be swapped with a magic space -->
- <string name="weak_space_swapping_symbols">.,)]}</string>
- <!-- Symbols that should strip a magic space -->
+ <!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
+ <string name="symbols_preceded_by_space">([{*&amp;;:!?</string>
+ <!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
+ <string name="symbols_followed_by_space">.,;:!?)]}*&amp;</string>
+ <!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="weak_space_stripping_symbols">"&#x0009;&#x0020;\n"\'-/_\"</string>
- <!-- Symbols that should promote magic spaces into real space -->
- <string name="phantom_space_promoting_symbols">;:!?([*&amp;@{&lt;&gt;+=|</string>
- <!-- Symbols that do NOT separate words -->
- <!-- Note that this is identical to the default value, but since the above ones are different
- and those variables only make sense together, this is kept here for readability. -->
- <string name="symbols_excluded_from_word_separators">\'-</string>
+ <string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
+ <!-- Word connectors -->
+ <string name="symbols_word_connectors">\'-</string>
</resources>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 193a0191e..70ace776f 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -20,18 +20,15 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Symbols that are suggested between words -->
<string name="suggested_punctuations">!,?,\\,,:,;,\",(,),\',-,/,@,_</string>
- <!-- Symbols that should be swapped with a weak space -->
- <string name="weak_space_swapping_symbols">.,;:!?)]}</string>
- <!-- Symbols that should strip a weak space -->
+ <!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
+ <string name="symbols_preceded_by_space">([{*&amp;</string>
+ <!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
+ <string name="symbols_followed_by_space">.,;:!?)]}*&amp;</string>
+ <!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="weak_space_stripping_symbols">"&#x0009;&#x0020;\n"/_\'-@\"</string>
- <!-- Symbols that should convert weak spaces into real space -->
- <string name="phantom_space_promoting_symbols">([*&amp;{&lt;&gt;+=|</string>
- <!-- Symbols that do NOT separate words -->
- <string name="symbols_excluded_from_word_separators">\'-</string>
- <!-- Word separator list is the union of all symbols except those that are not separators:
- weak_space_swapping_symbols | weak_space_stripping_symbols
- \ symbols_excluded_from_word_separators -->
+ <string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
+ <!-- Word connectors -->
+ <string name="symbols_word_connectors">\'-</string>
<!-- Symbol characters list that should switch back to the main layout -->
<!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK
U+2019: "’" RIGHT SINGLE QUOTATION MARK
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 5c5442708..fd7aac49f 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -376,4 +376,7 @@
<string name="prefs_keypress_vibration_duration_settings">Keypress vibration duration settings</string>
<!-- Title of the settings for keypress sound volume -->
<string name="prefs_keypress_sound_volume_settings">Keypress sound volume settings</string>
+
+ <!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] -->
+ <string name="button_default">Default</string>
</resources>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index 91ebac1da..0834adf20 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -71,7 +71,7 @@
>
<key-style
latin:styleName="enterKeyStyle"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="shiftEnterKeyStyle" />
</case>
<!-- Smiley in textShortMessage field.
Overrides common enter key style. -->
diff --git a/java/res/xml/key_styles_enter.xml b/java/res/xml/key_styles_enter.xml
index 3788ca8ba..61a515bad 100644
--- a/java/res/xml/key_styles_enter.xml
+++ b/java/res/xml/key_styles_enter.xml
@@ -99,7 +99,11 @@
latin:backgroundType="functional"
latin:parentStyle="navigateMoreKeysStyle" />
<key-style
- latin:styleName="defaultActionKeyStyle"
+ latin:styleName="shiftEnterKeyStyle"
+ latin:code="!code/key_shift_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ <key-style
+ latin:styleName="defaultActionEnterKeyStyle"
latin:code="!code/key_action_enter"
latin:keyIcon="!icon/undefined"
latin:backgroundType="action"
@@ -112,7 +116,7 @@
>
<key-style
latin:styleName="enterKeyStyle"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="shiftEnterKeyStyle" />
</case>
<case
latin:imeAction="actionGo"
@@ -120,7 +124,7 @@
<key-style
latin:styleName="enterKeyStyle"
latin:keyLabel="!text/label_go_key"
- latin:parentStyle="defaultActionKeyStyle" />
+ latin:parentStyle="defaultActionEnterKeyStyle" />
</case>
<case
latin:imeAction="actionNext"
@@ -128,7 +132,7 @@
<key-style
latin:styleName="enterKeyStyle"
latin:keyLabel="!text/label_next_key"
- latin:parentStyle="defaultActionKeyStyle" />
+ latin:parentStyle="defaultActionEnterKeyStyle" />
</case>
<case
latin:imeAction="actionPrevious"
@@ -136,7 +140,7 @@
<key-style
latin:styleName="enterKeyStyle"
latin:keyLabel="!text/label_previous_key"
- latin:parentStyle="defaultActionKeyStyle" />
+ latin:parentStyle="defaultActionEnterKeyStyle" />
</case>
<case
latin:imeAction="actionDone"
@@ -144,7 +148,7 @@
<key-style
latin:styleName="enterKeyStyle"
latin:keyLabel="!text/label_done_key"
- latin:parentStyle="defaultActionKeyStyle" />
+ latin:parentStyle="defaultActionEnterKeyStyle" />
</case>
<case
latin:imeAction="actionSend"
@@ -152,7 +156,7 @@
<key-style
latin:styleName="enterKeyStyle"
latin:keyLabel="!text/label_send_key"
- latin:parentStyle="defaultActionKeyStyle" />
+ latin:parentStyle="defaultActionEnterKeyStyle" />
</case>
<case
latin:imeAction="actionSearch"
@@ -160,7 +164,7 @@
<key-style
latin:styleName="enterKeyStyle"
latin:keyIcon="!icon/search_key"
- latin:parentStyle="defaultActionKeyStyle" />
+ latin:parentStyle="defaultActionEnterKeyStyle" />
</case>
<case
latin:imeAction="actionCustomLabel"
@@ -168,7 +172,7 @@
<key-style
latin:styleName="enterKeyStyle"
latin:keyLabelFlags="fromCustomActionLabel"
- latin:parentStyle="defaultActionKeyStyle" />
+ latin:parentStyle="defaultActionEnterKeyStyle" />
</case>
<!-- imeAction is either actionNone or actionUnspecified. -->
<default>
diff --git a/java/res/xml/spellchecker.xml b/java/res/xml/spellchecker.xml
index 66cd66280..813319c7b 100644
--- a/java/res/xml/spellchecker.xml
+++ b/java/res/xml/spellchecker.xml
@@ -57,18 +57,6 @@
/>
<subtype
android:label="@string/subtype_generic"
- android:subtypeLocale="cs"
- />
- <subtype
- android:label="@string/subtype_generic"
- android:subtypeLocale="nl"
- />
- <subtype
- android:label="@string/subtype_generic"
- android:subtypeLocale="hr"
- />
- <subtype
- android:label="@string/subtype_generic"
android:subtypeLocale="pt_BR"
/>
</spell-checker>
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
index 6a01b0190..ea86d98cb 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
@@ -209,7 +209,7 @@ public final class KeyCodeDescriptionMapper {
private String getDescriptionForActionKey(final Context context, final Keyboard keyboard,
final Key key) {
final KeyboardId keyboardId = keyboard.mId;
- final int actionId = keyboardId.imeActionId();
+ final int actionId = keyboardId.imeAction();
final int resId;
// Always use the label, if available.
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index f9ff7b089..02116ca08 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -172,12 +172,7 @@ public final class KeyboardId {
}
public int imeAction() {
- return InputTypeUtils.getActionIdFromEditorInfo(mEditorInfo);
- }
-
- public int imeActionId() {
- final int actionId = imeAction();
- return actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL ? mEditorInfo.actionId : actionId;
+ return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo);
}
@Override
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index b5ba98d85..0fdbb0d05 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -80,17 +80,17 @@ public final class ProximityInfo {
mNativeProximityInfo = createNativeProximityInfo(touchPositionCorrection);
}
- public static ProximityInfo createDummyProximityInfo() {
+ private static ProximityInfo createDummyProximityInfo() {
return new ProximityInfo("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null);
}
- public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity,
+ public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximityCharsArray,
final int rowSize, final int gridWidth, final int gridHeight) {
final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo();
spellCheckerProximityInfo.mNativeProximityInfo =
spellCheckerProximityInfo.setProximityInfoNative("",
rowSize, gridWidth, gridHeight, gridWidth, gridHeight,
- 1, proximity, 0, null, null, null, null, null, null, null, null);
+ 1, proximityCharsArray, 0, null, null, null, null, null, null, null, null);
return spellCheckerProximityInfo;
}
@@ -100,15 +100,13 @@ public final class ProximityInfo {
}
// TODO: Stop passing proximityCharsArray
- private native long setProximityInfoNative(
- String locale, int maxProximityCharsSize, int displayWidth,
- int displayHeight, int gridWidth, int gridHeight,
- int mostCommonKeyWidth, int[] proximityCharsArray,
- int keyCount, int[] keyXCoordinates, int[] keyYCoordinates,
- int[] keyWidths, int[] keyHeights, int[] keyCharCodes,
+ private static native long setProximityInfoNative(String locale, int maxProximityCharsSize,
+ int displayWidth, int displayHeight, int gridWidth, int gridHeight,
+ int mostCommonKeyWidth, int[] proximityCharsArray, int keyCount, int[] keyXCoordinates,
+ int[] keyYCoordinates, int[] keyWidths, int[] keyHeights, int[] keyCharCodes,
float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii);
- private native void releaseProximityInfoNative(long nativeProximityInfo);
+ private static native void releaseProximityInfoNative(long nativeProximityInfo);
private static boolean needsProximityInfo(final Key key) {
// Don't include special keys into ProximityInfo.
@@ -232,10 +230,10 @@ public final class ProximityInfo {
}
// TODO: Stop passing proximityCharsArray
- return setProximityInfoNative(mLocaleStr, MAX_PROXIMITY_CHARS_SIZE,
- mKeyboardMinWidth, mKeyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth,
- proximityCharsArray, keyCount, keyXCoordinates, keyYCoordinates, keyWidths,
- keyHeights, keyCharCodes, sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
+ return setProximityInfoNative(mLocaleStr, MAX_PROXIMITY_CHARS_SIZE, mKeyboardMinWidth,
+ mKeyboardHeight, mGridWidth, mGridHeight, mMostCommonKeyWidth, proximityCharsArray,
+ keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes,
+ sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii);
}
public long getNativeProximityInfo() {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
index a8407254f..4a8407cb5 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
@@ -138,6 +138,7 @@ final class GesturePreviewTrail {
}
private final RoundedLine mRoundedLine = new RoundedLine();
+ private final Rect mRoundedLineBounds = new Rect();
/**
* Draw gesture preview trail
@@ -149,6 +150,8 @@ final class GesturePreviewTrail {
*/
public boolean drawGestureTrail(final Canvas canvas, final Paint paint,
final Rect outBoundsRect, final Params params) {
+ // Initialize bounds rectangle.
+ outBoundsRect.setEmpty();
final int trailSize = mEventTimes.getLength();
if (trailSize == 0) {
return false;
@@ -171,39 +174,32 @@ final class GesturePreviewTrail {
if (startIndex < trailSize) {
paint.setColor(params.mTrailColor);
paint.setStyle(Paint.Style.FILL);
- final RoundedLine line = mRoundedLine;
+ final RoundedLine roundedLine = mRoundedLine;
int p1x = getXCoordValue(xCoords[startIndex]);
int p1y = yCoords[startIndex];
final int lastTime = sinceDown - eventTimes[startIndex];
- float maxWidth = getWidth(lastTime, params);
- float r1 = maxWidth / 2.0f;
- // Initialize bounds rectangle.
- outBoundsRect.set(p1x, p1y, p1x, p1y);
+ float r1 = getWidth(lastTime, params) / 2.0f;
for (int i = startIndex + 1; i < trailSize; i++) {
final int elapsedTime = sinceDown - eventTimes[i];
final int p2x = getXCoordValue(xCoords[i]);
final int p2y = yCoords[i];
- final float width = getWidth(elapsedTime, params);
- final float r2 = width / 2.0f;
+ final float r2 = getWidth(elapsedTime, params) / 2.0f;
// Draw trail line only when the current point isn't a down point.
if (!isDownEventXCoord(xCoords[i])) {
- final Path path = line.makePath(p1x, p1y, r1, p2x, p2y, r2);
+ final Path path = roundedLine.makePath(p1x, p1y, r1, p2x, p2y, r2);
if (path != null) {
final int alpha = getAlpha(elapsedTime, params);
paint.setAlpha(alpha);
canvas.drawPath(path, paint);
// Take union for the bounds.
- outBoundsRect.union(p2x, p2y);
- maxWidth = Math.max(maxWidth, width);
+ roundedLine.getBounds(mRoundedLineBounds);
+ outBoundsRect.union(mRoundedLineBounds);
}
}
p1x = p2x;
p1y = p2y;
r1 = r2;
}
- // Take care of trail line width.
- final int inset = -((int)maxWidth + 1);
- outBoundsRect.inset(inset, inset);
}
final int newSize = trailSize - startIndex;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
index 428e31ccd..0d852dde2 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
@@ -51,6 +51,7 @@ public final class KeyboardCodesSet {
"key_action_enter",
"key_action_next",
"key_action_previous",
+ "key_shift_enter",
"key_language_switch",
"key_research",
"key_unspecified",
@@ -86,6 +87,7 @@ public final class KeyboardCodesSet {
Constants.CODE_ACTION_ENTER,
Constants.CODE_ACTION_NEXT,
Constants.CODE_ACTION_PREVIOUS,
+ Constants.CODE_SHIFT_ENTER,
Constants.CODE_LANGUAGE_SWITCH,
Constants.CODE_RESEARCH,
Constants.CODE_UNSPECIFIED,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 6fefb809b..6ad7f9ba2 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -528,7 +528,7 @@ public final class KeyboardTextsSet {
// U+064E: "َ" ARABIC FATHA
// U+0640: "ـ" ARABIC TATWEEL
// In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
- /* 57 */ "!fixedColumnOrder!7,\u0655,\u0654,\u0652,\u064D,\u064C,\u064B,\u0651,\u0656,\u0670,\u0653,\u0650,\u064F,\u064E,\u0640\u0640\u0640|\u0640",
+ /* 57 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
/* 58 */ "\u0651",
// U+0661: "١" ARABIC-INDIC DIGIT ONE
/* 59 */ "\u0661",
@@ -1327,7 +1327,7 @@ public final class KeyboardTextsSet {
// U+064E: "َ" ARABIC FATHA
// U+0640: "ـ" ARABIC TATWEEL
// In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
- /* 57 */ "!fixedColumnOrder!7,\u0655,\u0652,\u0651,\u064C,\u064D,\u064B,\u0654,\u0656,\u0670,\u0653,\u064F,\u0650,\u064E,\u0640\u0640\u0640|\u0640",
+ /* 57 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
/* 58 */ "\u064B",
// U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
/* 59 */ "\u06F1",
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index bfb7b1fe0..7c87467bb 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -52,7 +52,8 @@ public final class PreviewPlacerView extends RelativeLayout {
private int mOffscreenOffsetY;
private Bitmap mOffscreenBuffer;
private final Canvas mOffscreenCanvas = new Canvas();
- private final Rect mOffscreenDirtyRect = new Rect();
+ private final Rect mOffscreenSrcRect = new Rect();
+ private final Rect mDirtyRect = new Rect();
private final Rect mGesturePreviewTrailBoundsRect = new Rect(); // per trail
private final GestureFloatingPreviewText mGestureFloatingPreviewText;
private boolean mShowSlidingKeyInputPreview;
@@ -193,6 +194,7 @@ public final class PreviewPlacerView extends RelativeLayout {
mOffscreenBuffer = Bitmap.createBitmap(
mOffscreenWidth, mOffscreenHeight, Bitmap.Config.ARGB_8888);
mOffscreenCanvas.setBitmap(mOffscreenBuffer);
+ mOffscreenCanvas.translate(0, mOffscreenOffsetY);
}
@Override
@@ -205,19 +207,18 @@ public final class PreviewPlacerView extends RelativeLayout {
mayAllocateOffscreenBuffer();
// Draw gesture trails to offscreen buffer.
final boolean needsUpdatingGesturePreviewTrail = drawGestureTrails(
- mOffscreenCanvas, mGesturePaint, mOffscreenDirtyRect);
+ mOffscreenCanvas, mGesturePaint, mDirtyRect);
+ if (needsUpdatingGesturePreviewTrail) {
+ mDrawingHandler.postUpdateGestureTrailPreview();
+ }
// Transfer offscreen buffer to screen.
- if (!mOffscreenDirtyRect.isEmpty()) {
- canvas.translate(0, - mOffscreenOffsetY);
- canvas.drawBitmap(mOffscreenBuffer, mOffscreenDirtyRect, mOffscreenDirtyRect,
- mGesturePaint);
- canvas.translate(0, mOffscreenOffsetY);
+ if (!mDirtyRect.isEmpty()) {
+ mOffscreenSrcRect.set(mDirtyRect);
+ mOffscreenSrcRect.offset(0, mOffscreenOffsetY);
+ canvas.drawBitmap(mOffscreenBuffer, mOffscreenSrcRect, mDirtyRect, null);
// Note: Defer clearing the dirty rectangle here because we will get cleared
// rectangle on the canvas.
}
- if (needsUpdatingGesturePreviewTrail) {
- mDrawingHandler.postUpdateGestureTrailPreview();
- }
}
mGestureFloatingPreviewText.onDraw(canvas);
if (mShowSlidingKeyInputPreview) {
@@ -235,10 +236,8 @@ public final class PreviewPlacerView extends RelativeLayout {
offscreenCanvas.drawRect(dirtyRect, paint);
}
dirtyRect.setEmpty();
-
- // Draw gesture trails to offscreen buffer.
- offscreenCanvas.translate(0, mOffscreenOffsetY);
boolean needsUpdatingGesturePreviewTrail = false;
+ // Draw gesture trails to offscreen buffer.
synchronized (mGesturePreviewTrails) {
// Trails count == fingers count that have ever been active.
final int trailsCount = mGesturePreviewTrails.size();
@@ -251,20 +250,9 @@ public final class PreviewPlacerView extends RelativeLayout {
dirtyRect.union(mGesturePreviewTrailBoundsRect);
}
}
- offscreenCanvas.translate(0, -mOffscreenOffsetY);
-
- // Clip dirty rectangle with offscreen buffer width/height.
- dirtyRect.offset(0, mOffscreenOffsetY);
- clipRect(dirtyRect, 0, 0, mOffscreenWidth, mOffscreenHeight);
return needsUpdatingGesturePreviewTrail;
}
- private static void clipRect(final Rect out, final int left, final int top, final int right,
- final int bottom) {
- out.set(Math.max(out.left, left), Math.max(out.top, top), Math.min(out.right, right),
- Math.min(out.bottom, bottom));
- }
-
public void setGestureFloatingPreviewText(final SuggestedWords suggestedWords) {
if (!mGestureFloatingPreviewText.isPreviewEnabled()) return;
mGestureFloatingPreviewText.setSuggetedWords(suggestedWords);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java b/java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java
index 1f5252077..cd6efc4b7 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/RoundedLine.java
@@ -15,6 +15,7 @@
package com.android.inputmethod.keyboard.internal;
import android.graphics.Path;
+import android.graphics.Rect;
import android.graphics.RectF;
public final class RoundedLine {
@@ -100,4 +101,10 @@ public final class RoundedLine {
mPath.close();
return mPath;
}
+
+ public void getBounds(final Rect outBounds) {
+ // Reuse mArc1 as working variable
+ mPath.computeBounds(mArc1, true /* unused */);
+ mArc1.roundOut(outBounds);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 448d25c73..27af3d1e0 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -35,24 +35,16 @@ public final class BinaryDictionary extends Dictionary {
public static final String DICTIONARY_PACK_AUTHORITY =
"com.android.inputmethod.latin.dictionarypack";
- /**
- * There is a difference between what java and native code can handle.
- * This value should only be used in BinaryDictionary.java
- * It is necessary to keep it at this value because some languages e.g. German have
- * really long words.
- */
+ // Must be identical to MAX_WORD_LENGTH in native/jni/src/defines.h
private static final int MAX_WORD_LENGTH = Constants.Dictionary.MAX_WORD_LENGTH;
- private static final int MAX_WORDS = 18;
- private static final int MAX_SPACES = 16;
-
- private static final int MAX_PREDICTIONS = 60;
- private static final int MAX_RESULTS = Math.max(MAX_PREDICTIONS, MAX_WORDS);
+ // Must be identical to MAX_RESULTS in native/jni/src/defines.h
+ private static final int MAX_RESULTS = 18;
private long mNativeDict;
private final Locale mLocale;
private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH];
private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS];
- private final int[] mSpaceIndices = new int[MAX_SPACES];
+ private final int[] mSpaceIndices = new int[MAX_RESULTS];
private final int[] mOutputScores = new int[MAX_RESULTS];
private final int[] mOutputTypes = new int[MAX_RESULTS];
@@ -80,16 +72,14 @@ public final class BinaryDictionary extends Dictionary {
/**
* Constructor for the binary dictionary. This is supposed to be called from the
* dictionary factory.
- * @param context the context to access the environment from.
* @param filename the name of the file to read through native code.
* @param offset the offset of the dictionary data within the file.
* @param length the length of the binary data.
* @param useFullEditDistance whether to use the full edit distance in suggestions
* @param dictType the dictionary type, as a human-readable string
*/
- public BinaryDictionary(final Context context, final String filename, final long offset,
- final long length, final boolean useFullEditDistance, final Locale locale,
- final String dictType) {
+ public BinaryDictionary(final String filename, final long offset, final long length,
+ final boolean useFullEditDistance, final Locale locale, final String dictType) {
super(dictType);
mLocale = locale;
mUseFullEditDistance = useFullEditDistance;
@@ -100,24 +90,22 @@ public final class BinaryDictionary extends Dictionary {
JniUtils.loadNativeLibrary();
}
- private native long openNative(String sourceDir, long dictOffset, long dictSize,
- int maxWordLength, int maxWords, int maxPredictions);
- private native void closeNative(long dict);
- private native int getFrequencyNative(long dict, int[] word);
- private native boolean isValidBigramNative(long dict, int[] word1, int[] word2);
- private native int getSuggestionsNative(long dict, long proximityInfo, long traverseSession,
- int[] xCoordinates, int[] yCoordinates, int[] times, int[] pointerIds,
- int[] inputCodePoints, int codesSize, int commitPoint, boolean isGesture,
- int[] prevWordCodePointArray, boolean useFullEditDistance, int[] outputCodePoints,
- int[] outputScores, int[] outputIndices, int[] outputTypes);
+ private static native long openNative(String sourceDir, long dictOffset, long dictSize);
+ private static native void closeNative(long dict);
+ private static native int getFrequencyNative(long dict, int[] word);
+ private static native boolean isValidBigramNative(long dict, int[] word1, int[] word2);
+ private static native int getSuggestionsNative(long dict, long proximityInfo,
+ long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
+ int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint,
+ boolean isGesture, int[] prevWordCodePointArray, boolean useFullEditDistance,
+ int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes);
private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
private static native int editDistanceNative(int[] before, int[] after);
// TODO: Move native dict into session
private final void loadDictionary(final String path, final long startOffset,
final long length) {
- mNativeDict = openNative(path, startOffset, length, MAX_WORD_LENGTH, MAX_WORDS,
- MAX_PREDICTIONS);
+ mNativeDict = openNative(path, startOffset, length);
}
@Override
@@ -146,16 +134,14 @@ public final class BinaryDictionary extends Dictionary {
}
final InputPointers ips = composer.getInputPointers();
- final int codesSize = isGesture ? ips.getPointerSize() : composerSize;
+ final int inputSize = isGesture ? ips.getPointerSize() : composerSize;
// proximityInfo and/or prevWordForBigrams may not be null.
- final int tmpCount = getSuggestionsNative(mNativeDict,
- proximityInfo.getNativeProximityInfo(), getTraverseSession(sessionId).getSession(),
- ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(),
- mInputCodePoints, codesSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray,
+ final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(),
+ getTraverseSession(sessionId).getSession(), ips.getXCoordinates(),
+ ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints,
+ inputSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray,
mUseFullEditDistance, mOutputCodePoints, mOutputScores, mSpaceIndices,
mOutputTypes);
- final int count = Math.min(tmpCount, MAX_PREDICTIONS);
-
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
for (int j = 0; j < count; ++j) {
if (composerSize > 0 && mOutputScores[j] < 1) break;
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 3a7772452..483504cfb 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -127,6 +127,7 @@ public final class Constants {
}
public static final class Dictionary {
+ // Must be identical to MAX_WORD_LENGTH in native/jni/src/defines.h
public static final int MAX_WORD_LENGTH = 48;
private Dictionary() {
@@ -183,8 +184,9 @@ public final class Constants {
public static final int CODE_ACTION_PREVIOUS = -9;
public static final int CODE_LANGUAGE_SWITCH = -10;
public static final int CODE_RESEARCH = -11;
+ public static final int CODE_SHIFT_ENTER = -12;
// Code value representing the code is not specified.
- public static final int CODE_UNSPECIFIED = -12;
+ public static final int CODE_UNSPECIFIED = -13;
public static boolean isLetterCode(final int code) {
return code >= CODE_SPACE;
diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
index ce1b64660..534e2116b 100644
--- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java
+++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
@@ -23,10 +23,10 @@ public final class DicTraverseSession {
JniUtils.loadNativeLibrary();
}
- private native long setDicTraverseSessionNative(String locale);
- private native void initDicTraverseSessionNative(long nativeDicTraverseSession,
+ private static native long setDicTraverseSessionNative(String locale);
+ private static native void initDicTraverseSessionNative(long nativeDicTraverseSession,
long dictionary, int[] previousWord, int previousWordLength);
- private native void releaseDicTraverseSessionNative(long nativeDicTraverseSession);
+ private static native void releaseDicTraverseSessionNative(long nativeDicTraverseSession);
private long mNativeDicTraverseSession;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index f381973ae..22cf5b38d 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -58,9 +58,8 @@ public final class DictionaryFactory {
BinaryDictionaryGetter.getDictionaryFiles(locale, context);
if (null != assetFileList) {
for (final AssetFileAddress f : assetFileList) {
- final BinaryDictionary binaryDictionary =
- new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength,
- useFullEditDistance, locale, Dictionary.TYPE_MAIN);
+ final BinaryDictionary binaryDictionary = new BinaryDictionary(f.mFilename,
+ f.mOffset, f.mLength, useFullEditDistance, locale, Dictionary.TYPE_MAIN);
if (binaryDictionary.isValidDictionary()) {
dictList.add(binaryDictionary);
}
@@ -112,7 +111,7 @@ public final class DictionaryFactory {
Log.e(TAG, "sourceDir is not a file: " + sourceDir);
return null;
}
- return new BinaryDictionary(context, sourceDir, afd.getStartOffset(), afd.getLength(),
+ return new BinaryDictionary(sourceDir, afd.getStartOffset(), afd.getLength(),
false /* useFullEditDistance */, locale, Dictionary.TYPE_MAIN);
} catch (android.content.res.Resources.NotFoundException e) {
Log.e(TAG, "Could not find the resource");
@@ -130,17 +129,16 @@ public final class DictionaryFactory {
/**
* Create a dictionary from passed data. This is intended for unit tests only.
- * @param context the test context to create this data from.
* @param dictionary the file to read
* @param startOffset the offset in the file where the data starts
* @param length the length of the data
* @param useFullEditDistance whether to use the full edit distance in suggestions
* @return the created dictionary, or null.
*/
- public static Dictionary createDictionaryForTest(Context context, File dictionary,
- long startOffset, long length, final boolean useFullEditDistance, Locale locale) {
+ public static Dictionary createDictionaryForTest(File dictionary, long startOffset, long length,
+ final boolean useFullEditDistance, Locale locale) {
if (dictionary.isFile()) {
- return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length,
+ return new BinaryDictionary(dictionary.getAbsolutePath(), startOffset, length,
useFullEditDistance, locale, Dictionary.TYPE_MAIN);
} else {
Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath());
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 47adaa8ed..2c7fdcc93 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -279,9 +279,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
final long length = file.length();
// Build the new binary dictionary
- final BinaryDictionary newBinaryDictionary =
- new BinaryDictionary(mContext, filename, 0, length, true /* useFullEditDistance */,
- null, mDictType);
+ final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0, length,
+ true /* useFullEditDistance */, null, mDictType);
if (mBinaryDictionary != null) {
// Ensure all threads accessing the current dictionary have finished before swapping in
diff --git a/java/src/com/android/inputmethod/latin/InputTypeUtils.java b/java/src/com/android/inputmethod/latin/InputTypeUtils.java
index 55414b809..e2eacb3f0 100644
--- a/java/src/com/android/inputmethod/latin/InputTypeUtils.java
+++ b/java/src/com/android/inputmethod/latin/InputTypeUtils.java
@@ -105,7 +105,7 @@ public final class InputTypeUtils implements InputType {
return true;
}
- public static int getActionIdFromEditorInfo(final EditorInfo editorInfo) {
+ public static int getImeOptionsActionIdFromEditorInfo(final EditorInfo editorInfo) {
final int actionId = editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION;
if ((editorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
return EditorInfo.IME_ACTION_NONE;
@@ -115,4 +115,9 @@ public final class InputTypeUtils implements InputType {
return actionId;
}
}
+
+ public static int getConcreteActionIdFromEditorInfo(final EditorInfo editorInfo) {
+ final int actionId = getImeOptionsActionIdFromEditorInfo(editorInfo);
+ return actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL ? editorInfo.actionId : actionId;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java
index 488a6fcf2..a4019e906 100644
--- a/java/src/com/android/inputmethod/latin/LastComposedWord.java
+++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java
@@ -45,19 +45,21 @@ public final class LastComposedWord {
public final String mCommittedWord;
public final String mSeparatorString;
public final String mPrevWord;
+ public final int mCapitalizedMode;
public final InputPointers mInputPointers =
new InputPointers(Constants.Dictionary.MAX_WORD_LENGTH);
private boolean mActive;
public static final LastComposedWord NOT_A_COMPOSED_WORD =
- new LastComposedWord(null, null, "", "", NOT_A_SEPARATOR, null);
+ new LastComposedWord(null, null, "", "", NOT_A_SEPARATOR, null,
+ WordComposer.CAPS_MODE_OFF);
// Warning: this is using the passed objects as is and fully expects them to be
// immutable. Do not fiddle with their contents after you passed them to this constructor.
public LastComposedWord(final int[] primaryKeyCodes, final InputPointers inputPointers,
- final String typedWord, final String committedWord,
- final String separatorString, final String prevWord) {
+ final String typedWord, final String committedWord, final String separatorString,
+ final String prevWord, final int capitalizedMode) {
mPrimaryKeyCodes = primaryKeyCodes;
if (inputPointers != null) {
mInputPointers.copy(inputPointers);
@@ -67,6 +69,7 @@ public final class LastComposedWord {
mSeparatorString = separatorString;
mActive = true;
mPrevWord = prevWord;
+ mCapitalizedMode = capitalizedMode;
}
public void deactivate() {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 152118d98..d02c4df7e 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -166,6 +166,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private boolean mExpectingUpdateSelection;
private int mDeleteCount;
private long mLastKeyTime;
+ private int mActionId;
// Member variables for remembering the current device orientation.
private int mDisplayOrientation;
@@ -754,6 +755,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mLastSelectionStart = editorInfo.initialSelStart;
mLastSelectionEnd = editorInfo.initialSelEnd;
+ mActionId = InputTypeUtils.getConcreteActionIdFromEditorInfo(editorInfo);
mHandler.cancelUpdateSuggestionStrip();
mHandler.cancelDoubleSpacePeriodTimer();
@@ -1223,7 +1225,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mPositionalInfoForUserDictPendingAddition =
new PositionalInfoForUserDictPendingAddition(
- word, mLastSelectionEnd, getCurrentInputEditorInfo());
+ word, mLastSelectionEnd, getCurrentInputEditorInfo(),
+ mLastComposedWord.mCapitalizedMode);
mUserDictionary.addWordToUserDictionary(word, 128);
}
@@ -1272,10 +1275,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
return mOptionsDialog != null && mOptionsDialog.isShowing();
}
- private static int getActionId(final Keyboard keyboard) {
- return keyboard != null ? keyboard.mId.imeActionId() : EditorInfo.IME_ACTION_NONE;
- }
-
private void performEditorAction(final int actionId) {
mConnection.performEditorAction(actionId);
}
@@ -1301,13 +1300,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
private void sendKeyCodePoint(final int code) {
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_sendKeyCodePoint(code);
+ }
// TODO: Remove this special handling of digit letters.
// For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}.
if (code >= '0' && code <= '9') {
sendDownUpKeyEventForBackwardCompatibility(code - '0' + KeyEvent.KEYCODE_0);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_sendKeyCodePoint(code);
- }
return;
}
@@ -1327,6 +1326,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Implementation of {@link KeyboardActionListener}.
@Override
public void onCodeInput(final int primaryCode, final int x, final int y) {
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_onCodeInput(primaryCode, x, y);
+ }
final long when = SystemClock.uptimeMillis();
if (primaryCode != Constants.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
mDeleteCount = 0;
@@ -1366,9 +1368,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
case Constants.CODE_SHORTCUT:
mSubtypeSwitcher.switchToShortcutIME(this);
break;
- case Constants.CODE_ACTION_ENTER:
- performEditorAction(getActionId(switcher.getKeyboard()));
- break;
case Constants.CODE_ACTION_NEXT:
performEditorAction(EditorInfo.IME_ACTION_NEXT);
break;
@@ -1383,32 +1382,19 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
ResearchLogger.getInstance().onResearchKeySelected(this);
}
break;
- default:
- mSpaceState = SPACE_STATE_NONE;
- if (mSettings.getCurrent().isWordSeparator(primaryCode)) {
- didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
- } else {
- if (SPACE_STATE_PHANTOM == spaceState) {
- if (ProductionFlag.IS_INTERNAL) {
- if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) {
- Stats.onAutoCorrection(
- "", mWordComposer.getTypedWord(), " ", mWordComposer);
- }
- }
- commitTyped(LastComposedWord.NOT_A_SEPARATOR);
- }
- final int keyX, keyY;
- final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
- if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) {
- keyX = x;
- keyY = y;
- } else {
- keyX = Constants.NOT_A_COORDINATE;
- keyY = Constants.NOT_A_COORDINATE;
- }
- handleCharacter(primaryCode, keyX, keyY, spaceState);
+ case Constants.CODE_ACTION_ENTER:
+ if (EditorInfo.IME_ACTION_NONE != mActionId
+ && EditorInfo.IME_ACTION_UNSPECIFIED != mActionId) {
+ performEditorAction(mActionId);
+ break;
}
- mExpectingUpdateSelection = true;
+ didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState);
+ break;
+ case Constants.CODE_SHIFT_ENTER:
+ didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState);
+ break;
+ default:
+ didAutoCorrect = handleNonSpecialCharacter(primaryCode, x, y, spaceState);
break;
}
switcher.onCodeInput(primaryCode);
@@ -1420,9 +1406,38 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mEnteredText = null;
}
mConnection.endBatchEdit();
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_onCodeInput(primaryCode, x, y);
+ }
+
+ private boolean handleNonSpecialCharacter(final int primaryCode, final int x, final int y,
+ final int spaceState) {
+ mSpaceState = SPACE_STATE_NONE;
+ final boolean didAutoCorrect;
+ if (mSettings.getCurrent().isWordSeparator(primaryCode)) {
+ didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
+ } else {
+ didAutoCorrect = false;
+ if (SPACE_STATE_PHANTOM == spaceState) {
+ if (ProductionFlag.IS_INTERNAL) {
+ if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) {
+ Stats.onAutoCorrection(
+ "", mWordComposer.getTypedWord(), " ", mWordComposer);
+ }
+ }
+ commitTyped(LastComposedWord.NOT_A_SEPARATOR);
+ }
+ final int keyX, keyY;
+ final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
+ if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) {
+ keyX = x;
+ keyY = y;
+ } else {
+ keyX = Constants.NOT_A_COORDINATE;
+ keyY = Constants.NOT_A_COORDINATE;
+ }
+ handleCharacter(primaryCode, keyX, keyY, spaceState);
}
+ mExpectingUpdateSelection = true;
+ return didAutoCorrect;
}
// Called from PointerTracker through the KeyboardActionListener interface
@@ -1479,12 +1494,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mSpaceState = SPACE_STATE_PHANTOM;
} else {
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
- // TODO: reverse this logic. We should have the means to determine whether a character
- // should usually be followed by a space, and it should be more readable.
- if (Constants.NOT_A_CODE != codePointBeforeCursor
- && !Character.isWhitespace(codePointBeforeCursor)
- && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(codePointBeforeCursor)
- && !mSettings.getCurrent().isWeakSpaceStripper(codePointBeforeCursor)) {
+ if (mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) {
mSpaceState = SPACE_STATE_PHANTOM;
}
}
@@ -1667,7 +1677,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (mWordComposer.isBatchMode()) {
if (ProductionFlag.IS_EXPERIMENTAL) {
final String word = mWordComposer.getTypedWord();
- ResearchLogger.latinIME_handleBackspace_batch(word);
+ ResearchLogger.latinIME_handleBackspace_batch(word, 1);
ResearchLogger.getInstance().uncommitCurrentLogUnit(
word, false /* dumpCurrentLogUnit */);
}
@@ -1718,14 +1728,17 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// We should backspace one char and restart suggestion if at the end of a word.
if (mLastSelectionStart != mLastSelectionEnd) {
// If there is a selection, remove it.
- final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart;
+ final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart;
mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd);
// Reset mLastSelectionEnd to mLastSelectionStart. This is what is supposed to
// happen, and if it's wrong, the next call to onUpdateSelection will correct it,
// but we want to set it right away to avoid it being used with the wrong values
// later (typically, in a subsequent press on backspace).
mLastSelectionEnd = mLastSelectionStart;
- mConnection.deleteSurroundingText(lengthToDelete, 0);
+ mConnection.deleteSurroundingText(numCharsDeleted, 0);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_handleBackspace(numCharsDeleted);
+ }
} else {
// There is no selection, just delete one character.
if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) {
@@ -1742,8 +1755,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
} else {
mConnection.deleteSurroundingText(1, 0);
}
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_handleBackspace(1);
+ }
if (mDeleteCount > DELETE_ACCELERATE_AT) {
mConnection.deleteSurroundingText(1, 0);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_handleBackspace(1);
+ }
}
}
if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
@@ -1752,25 +1771,22 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
+ /*
+ * Strip a trailing space if necessary and returns whether it's a swap weak space situation.
+ */
private boolean maybeStripSpace(final int code,
final int spaceState, final boolean isFromSuggestionStrip) {
if (Constants.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
mConnection.removeTrailingSpace();
return false;
- } else if ((SPACE_STATE_WEAK == spaceState
- || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
+ }
+ if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
&& isFromSuggestionStrip) {
- if (mSettings.getCurrent().isWeakSpaceSwapper(code)) {
- return true;
- } else {
- if (mSettings.getCurrent().isWeakSpaceStripper(code)) {
- mConnection.removeTrailingSpace();
- }
- return false;
- }
- } else {
- return false;
+ if (mSettings.getCurrent().isUsuallyPrecededBySpace(code)) return false;
+ if (mSettings.getCurrent().isUsuallyFollowedBySpace(code)) return true;
+ mConnection.removeTrailingSpace();
}
+ return false;
}
private void handleCharacter(final int primaryCode, final int x,
@@ -1778,7 +1794,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
boolean isComposingWord = mWordComposer.isComposingWord();
if (SPACE_STATE_PHANTOM == spaceState &&
- !mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode)) {
+ !mSettings.getCurrent().isWordConnector(primaryCode)) {
if (isComposingWord) {
// Sanity check
throw new RuntimeException("Should not be composing here");
@@ -1790,7 +1806,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
// thread here.
if (!isComposingWord && (isAlphabet(primaryCode)
- || mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode))
+ || mSettings.getCurrent().isWordConnector(primaryCode))
&& mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) &&
!mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
// Reset entirely the composing state anyway, then start composing a new word unless
@@ -1844,7 +1860,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private boolean handleSeparator(final int primaryCode, final int x, final int y,
final int spaceState) {
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_handleSeparator();
+ ResearchLogger.recordTimeForLogUnitSplit();
}
boolean didAutoCorrect = false;
// Handle separator
@@ -1862,7 +1878,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
Constants.SUGGESTION_STRIP_COORDINATE == x);
if (SPACE_STATE_PHANTOM == spaceState &&
- mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) {
+ mSettings.getCurrent().isUsuallyPrecededBySpace(primaryCode)) {
promotePhantomSpace();
}
sendKeyCodePoint(primaryCode);
@@ -1877,16 +1893,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mHandler.startDoubleSpacePeriodTimer();
- if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
- mHandler.postUpdateSuggestionStrip();
- }
+ mHandler.postUpdateSuggestionStrip();
} else {
if (swapWeakSpace) {
swapSwapperAndSpace();
mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
} else if (SPACE_STATE_PHANTOM == spaceState
- && !mSettings.getCurrent().isWeakSpaceStripper(primaryCode)
- && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) {
+ && mSettings.getCurrent().isUsuallyFollowedBySpace(primaryCode)) {
// If we are in phantom space state, and the user presses a separator, we want to
// stay in phantom space state so that the next keypress has a chance to add the
// space. For example, if I type "Good dat", pick "day" from the suggestion strip
@@ -2125,7 +2138,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_punctuationSuggestion(index, suggestion,
- false /* isBatchMode */);
+ false /* isBatchMode */, suggestedWords.mIsPrediction);
}
return;
}
@@ -2135,9 +2148,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// In the batch input mode, a manually picked suggested word should just replace
// the current batch input text and there is no need for a phantom space.
&& !mWordComposer.isBatchMode()) {
- int firstChar = Character.codePointAt(suggestion, 0);
- if ((!mSettings.getCurrent().isWeakSpaceStripper(firstChar))
- && (!mSettings.getCurrent().isWeakSpaceSwapper(firstChar))) {
+ final int firstChar = Character.codePointAt(suggestion, 0);
+ if (!mSettings.getCurrent().isWordSeparator(firstChar)
+ || mSettings.getCurrent().isUsuallyPrecededBySpace(firstChar)) {
promotePhantomSpace();
}
}
@@ -2312,7 +2325,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord,
- mWordComposer.isBatchMode());
+ mWordComposer.isBatchMode(), mLastComposedWord.mSeparatorString);
ResearchLogger.getInstance().uncommitCurrentLogUnit(committedWord,
true /* dumpCurrentLogUnit */);
}
@@ -2327,6 +2340,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
public void promotePhantomSpace() {
if (mSettings.getCurrent().shouldInsertSpacesAutomatically()) {
sendKeyCodePoint(Constants.CODE_SPACE);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_promotePhantomSpace();
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
index 1fd25636c..a33cefcd6 100644
--- a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
+++ b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
@@ -33,13 +33,15 @@ public final class PositionalInfoForUserDictPendingAddition {
final private String mOriginalWord;
final private int mCursorPos; // Position of the cursor after the word
final private EditorInfo mEditorInfo; // On what binding this has been added
+ final private int mCapitalizedMode;
private String mActualWordBeingAdded;
public PositionalInfoForUserDictPendingAddition(final String word, final int cursorPos,
- final EditorInfo editorInfo) {
+ final EditorInfo editorInfo, final int capitalizedMode) {
mOriginalWord = word;
mCursorPos = cursorPos;
mEditorInfo = editorInfo;
+ mCapitalizedMode = capitalizedMode;
}
public void setActualWordBeingAdded(final String actualWordBeingAdded) {
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index f7268fc33..0e75533f5 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -577,11 +577,11 @@ public final class RichInputConnection {
final CharSequence before = getTextBeforeCursor(1, 0);
final CharSequence after = getTextAfterCursor(1, 0);
if (!TextUtils.isEmpty(before) && !settingsValues.isWordSeparator(before.charAt(0))
- && !settingsValues.isSymbolExcludedFromWordSeparators(before.charAt(0))) {
+ && !settingsValues.isWordConnector(before.charAt(0))) {
return true;
}
if (!TextUtils.isEmpty(after) && !settingsValues.isWordSeparator(after.charAt(0))
- && !settingsValues.isSymbolExcludedFromWordSeparators(after.charAt(0))) {
+ && !settingsValues.isWordConnector(after.charAt(0))) {
return true;
}
return false;
@@ -633,12 +633,9 @@ public final class RichInputConnection {
final char firstChar = word.charAt(0); // we just tested that word is not empty
if (word.length() == 1 && !Character.isLetter(firstChar)) return null;
- // We only suggest on words that start with a letter or a symbol that is excluded from
- // word separators (see #handleCharacterWhileInBatchEdit).
- if (!(Character.isLetter(firstChar)
- || settings.isSymbolExcludedFromWordSeparators(firstChar))) {
- return null;
- }
+ // We don't restart suggestion if the first character is not a letter, because we don't
+ // start composing when the first character is not a letter.
+ if (!Character.isLetter(firstChar)) return null;
return word;
}
diff --git a/java/src/com/android/inputmethod/latin/SeekBarDialog.java b/java/src/com/android/inputmethod/latin/SeekBarDialog.java
index e576c0984..c736d1b1a 100644
--- a/java/src/com/android/inputmethod/latin/SeekBarDialog.java
+++ b/java/src/com/android/inputmethod/latin/SeekBarDialog.java
@@ -30,6 +30,8 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
public interface Listener {
public void onPositiveButtonClick(final SeekBarDialog dialog);
public void onNegativeButtonClick(final SeekBarDialog dialog);
+ public void onNeutralButtonClick(final SeekBarDialog dialog);
+ public void onDismiss(final SeekBarDialog dialog);
public void onProgressChanged(final SeekBarDialog dialog);
public void onStartTrackingTouch(final SeekBarDialog dialog);
public void onStopTrackingTouch(final SeekBarDialog dialog);
@@ -39,7 +41,11 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
@Override
public void onPositiveButtonClick(final SeekBarDialog dialog) {}
@Override
- public void onNegativeButtonClick(final SeekBarDialog dialog) { dialog.dismiss(); }
+ public void onNegativeButtonClick(final SeekBarDialog dialog) {}
+ @Override
+ public void onNeutralButtonClick(final SeekBarDialog dialog) {}
+ @Override
+ public void onDismiss(final SeekBarDialog dialog) {}
@Override
public void onProgressChanged(final SeekBarDialog dialog) {}
@Override
@@ -63,6 +69,9 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
dialogBuilder.setView(builder.mView);
dialogBuilder.setPositiveButton(android.R.string.ok, this);
dialogBuilder.setNegativeButton(android.R.string.cancel, this);
+ if (builder.mNeutralButtonTextResId != 0) {
+ dialogBuilder.setNeutralButton(builder.mNeutralButtonTextResId, this);
+ }
mDialog = dialogBuilder.create();
mListener = (builder.mListener == null) ? EMPTY_ADAPTER : builder.mListener;
mValueView = (TextView)builder.mView.findViewById(R.id.seek_bar_dialog_value);
@@ -101,15 +110,21 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
}
@Override
- public void onClick(final DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
+ public void onClick(final DialogInterface dialog, final int which) {
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
mListener.onPositiveButtonClick(this);
- return;
- }
- if (which == DialogInterface.BUTTON_NEGATIVE) {
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
mListener.onNegativeButtonClick(this);
+ break;
+ case DialogInterface.BUTTON_NEUTRAL:
+ mListener.onNeutralButtonClick(this);
+ break;
+ default:
return;
}
+ mListener.onDismiss(this);
}
@Override
@@ -135,6 +150,7 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
final AlertDialog.Builder mDialogBuilder;
final View mView;
+ int mNeutralButtonTextResId;
int mMaxValue;
int mValueFormatResId;
int mValue;
@@ -150,8 +166,14 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
return this;
}
+ public Builder setNeutralButtonText(final int resId) {
+ mNeutralButtonTextResId = resId;
+ return this;
+ }
+
public Builder setMaxValue(final int max) {
mMaxValue = max;
+ mValue = Math.min(mValue, max);
return this;
}
@@ -161,7 +183,7 @@ public final class SeekBarDialog implements DialogInterface.OnClickListener,
}
public Builder setValue(final int value) {
- mValue = value;
+ mValue = Math.min(value, mMaxValue);
return this;
}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index c5930a935..866bef0f2 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -167,19 +167,21 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static float readKeypressSoundVolume(final SharedPreferences prefs,
final Resources res) {
final float volume = prefs.getFloat(PREF_KEYPRESS_SOUND_VOLUME, -1.0f);
- if (volume >= 0) {
- return volume;
- }
+ return (volume >= 0) ? volume : readDefaultKeypressSoundVolume(res);
+ }
+
+ public static float readDefaultKeypressSoundVolume(final Resources res) {
return Float.parseFloat(
ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes));
}
- public static int readVibrationDuration(final SharedPreferences prefs,
+ public static int readKeypressVibrationDuration(final SharedPreferences prefs,
final Resources res) {
final int ms = prefs.getInt(PREF_VIBRATION_DURATION_SETTINGS, -1);
- if (ms >= 0) {
- return ms;
- }
+ return (ms >= 0) ? ms : readDefaultKeypressVibrationDuration(res);
+ }
+
+ public static int readDefaultKeypressVibrationDuration(final Resources res) {
return Integer.parseInt(
ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations));
}
diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java
index 507a37b7c..6a4371835 100644
--- a/java/src/com/android/inputmethod/latin/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java
@@ -180,7 +180,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment
});
mKeypressVibrationDurationSettingsPref.setSummary(
res.getString(R.string.settings_keypress_vibration_duration,
- Settings.readVibrationDuration(prefs, res)));
+ Settings.readKeypressVibrationDuration(prefs, res)));
}
mKeypressSoundVolumeSettingsPref =
@@ -308,10 +308,29 @@ public final class SettingsFragment extends InputMethodSettingsFragment
final Context context = getActivity();
final PreferenceScreen settingsPref = mKeypressVibrationDurationSettingsPref;
final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() {
+ private void writePreference(final SharedPreferences sp, final int value) {
+ sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, value).apply();
+ }
+
+ private void feedbackSettingsValue(final int value) {
+ AudioAndHapticFeedbackManager.getInstance().vibrate(value);
+ }
+
@Override
public void onPositiveButtonClick(final SeekBarDialog dialog) {
- final int ms = dialog.getValue();
- sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply();
+ writePreference(sp, dialog.getValue());
+ }
+
+ @Override
+ public void onNeutralButtonClick(final SeekBarDialog dialog) {
+ final int defaultValue =
+ Settings.readDefaultKeypressVibrationDuration(context.getResources());
+ dialog.setValue(defaultValue, false /* fromUser */);
+ writePreference(sp, defaultValue);
+ }
+
+ @Override
+ public void onDismiss(final SeekBarDialog dialog) {
if (settingsPref != null) {
settingsPref.setSummary(dialog.getValueText());
}
@@ -319,13 +338,13 @@ public final class SettingsFragment extends InputMethodSettingsFragment
@Override
public void onStopTrackingTouch(final SeekBarDialog dialog) {
- final int ms = dialog.getValue();
- AudioAndHapticFeedbackManager.getInstance().vibrate(ms);
+ feedbackSettingsValue(dialog.getValue());
}
};
- final int currentMs = Settings.readVibrationDuration(sp, getResources());
+ final int currentMs = Settings.readKeypressVibrationDuration(sp, getResources());
final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context);
builder.setTitle(R.string.prefs_keypress_vibration_duration_settings)
+ .setNeutralButtonText(R.string.button_default)
.setListener(listener)
.setMaxValue(AudioAndHapticFeedbackManager.MAX_KEYPRESS_VIBRATION_DURATION)
.setValueFromat(R.string.settings_keypress_vibration_duration)
@@ -348,10 +367,29 @@ public final class SettingsFragment extends InputMethodSettingsFragment
final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
final PreferenceScreen settingsPref = mKeypressSoundVolumeSettingsPref;
final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() {
+ private void writePreference(final SharedPreferences sp, final float value) {
+ sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, value).apply();
+ }
+
+ private void feedbackSettingsValue(final float value) {
+ am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, value);
+ }
+
@Override
public void onPositiveButtonClick(final SeekBarDialog dialog) {
- final float volume = dialog.getValue() / PERCENT_FLOAT;
- sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply();
+ writePreference(sp, dialog.getValue() / PERCENT_FLOAT);
+ }
+
+ @Override
+ public void onNeutralButtonClick(final SeekBarDialog dialog) {
+ final float defaultValue =
+ Settings.readDefaultKeypressSoundVolume(context.getResources());
+ dialog.setValue((int)(defaultValue * PERCENT_INT), false /* fromUser */);
+ writePreference(sp, defaultValue);
+ }
+
+ @Override
+ public void onDismiss(final SeekBarDialog dialog) {
if (settingsPref != null) {
settingsPref.setSummary(dialog.getValueText());
}
@@ -359,13 +397,13 @@ public final class SettingsFragment extends InputMethodSettingsFragment
@Override
public void onStopTrackingTouch(final SeekBarDialog dialog) {
- final float volume = dialog.getValue() / PERCENT_FLOAT;
- am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, volume);
+ feedbackSettingsValue(dialog.getValue() / PERCENT_FLOAT);
}
};
final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context);
final int currentVolumeInt = getCurrentKeyPressSoundVolumePercent(sp, getResources());
builder.setTitle(R.string.prefs_keypress_sound_volume_settings)
+ .setNeutralButtonText(R.string.button_default)
.setListener(listener)
.setMaxValue(PERCENT_INT)
.setValue(currentVolumeInt)
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 9a2024618..1e3bdf0fd 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -37,11 +37,10 @@ public final class SettingsValues {
// From resources:
public final int mDelayUpdateOldSuggestions;
- public final String mWeakSpaceStrippers;
- public final String mWeakSpaceSwappers;
- private final String mPhantomSpacePromotingSymbols;
+ public final int[] mSymbolsPrecededBySpace;
+ public final int[] mSymbolsFollowedBySpace;
+ public final int[] mWordConnectors;
public final SuggestedWords mSuggestPuncList;
- private final String mSymbolsExcludedFromWordSeparators;
public final String mWordSeparators;
public final CharSequence mHintToSaveText;
@@ -79,25 +78,19 @@ public final class SettingsValues {
final InputAttributes inputAttributes) {
// Get the resources
mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
- mWeakSpaceStrippers = res.getString(R.string.weak_space_stripping_symbols);
- mWeakSpaceSwappers = res.getString(R.string.weak_space_swapping_symbols);
- mPhantomSpacePromotingSymbols = res.getString(R.string.phantom_space_promoting_symbols);
- if (LatinImeLogger.sDBG) {
- final int length = mWeakSpaceStrippers.length();
- for (int i = 0; i < length; i = mWeakSpaceStrippers.offsetByCodePoints(i, 1)) {
- if (isWeakSpaceSwapper(mWeakSpaceStrippers.codePointAt(i))) {
- throw new RuntimeException("Char code " + mWeakSpaceStrippers.codePointAt(i)
- + " is both a weak space swapper and stripper.");
- }
- }
- }
+ mSymbolsPrecededBySpace =
+ StringUtils.toCodePointArray(res.getString(R.string.symbols_preceded_by_space));
+ Arrays.sort(mSymbolsPrecededBySpace);
+ mSymbolsFollowedBySpace =
+ StringUtils.toCodePointArray(res.getString(R.string.symbols_followed_by_space));
+ Arrays.sort(mSymbolsFollowedBySpace);
+ mWordConnectors =
+ StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors));
+ Arrays.sort(mWordConnectors);
final String[] suggestPuncsSpec = KeySpecParser.parseCsvString(
res.getString(R.string.suggested_punctuations), null);
mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
- mSymbolsExcludedFromWordSeparators =
- res.getString(R.string.symbols_excluded_from_word_separators);
- mWordSeparators = createWordSeparators(mWeakSpaceStrippers, mWeakSpaceSwappers,
- mSymbolsExcludedFromWordSeparators, res);
+ mWordSeparators = res.getString(R.string.symbols_word_separators);
mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
// Store the input attributes
@@ -128,7 +121,7 @@ public final class SettingsValues {
mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res);
// Compute other readable settings
- mKeypressVibrationDuration = Settings.readVibrationDuration(prefs, res);
+ mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res);
mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res);
mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res);
mAutoCorrectionThreshold = readAutoCorrectionThreshold(res,
@@ -169,25 +162,16 @@ public final class SettingsValues {
return mWordSeparators.contains(String.valueOf((char)code));
}
- public boolean isSymbolExcludedFromWordSeparators(final int code) {
- return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
- }
-
- // TODO: use "Phantom" instead of "Weak" in this method name
- public boolean isWeakSpaceStripper(final int code) {
- // TODO: this does not work if the code does not fit in a char
- return mWeakSpaceStrippers.contains(String.valueOf((char)code));
+ public boolean isWordConnector(final int code) {
+ return Arrays.binarySearch(mWordConnectors, code) >= 0;
}
- // TODO: use "Phantom" instead of "Weak" in this method name
- public boolean isWeakSpaceSwapper(final int code) {
- // TODO: this does not work if the code does not fit in a char
- return mWeakSpaceSwappers.contains(String.valueOf((char)code));
+ public boolean isUsuallyPrecededBySpace(final int code) {
+ return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0;
}
- public boolean isPhantomSpacePromotingSymbol(final int code) {
- // TODO: this does not work if the code does not fit in a char
- return mPhantomSpacePromotingSymbols.contains(String.valueOf((char)code));
+ public boolean isUsuallyFollowedBySpace(final int code) {
+ return Arrays.binarySearch(mSymbolsFollowedBySpace, code) >= 0;
}
public boolean shouldInsertSpacesAutomatically() {
@@ -239,18 +223,6 @@ public final class SettingsValues {
false /* isPrediction */);
}
- private static String createWordSeparators(final String weakSpaceStrippers,
- final String weakSpaceSwappers, final String symbolsExcludedFromWordSeparators,
- final Resources res) {
- String wordSeparators = weakSpaceStrippers + weakSpaceSwappers
- + res.getString(R.string.phantom_space_promoting_symbols);
- for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) {
- wordSeparators = wordSeparators.replace(
- symbolsExcludedFromWordSeparators.substring(i, i + 1), "");
- }
- return wordSeparators;
- }
-
private static final int SUGGESTION_VISIBILITY_SHOW_VALUE =
R.string.prefs_suggestion_visibility_show_value;
private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE =
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 3dc2ba95b..2abf75da4 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -72,9 +72,8 @@ public final class Suggest {
}
@UsedForTesting
- Suggest(final Context context, final File dictionary,
- final long startOffset, final long length, final Locale locale) {
- final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(context, dictionary,
+ Suggest(final File dictionary, final long startOffset, final long length, final Locale locale) {
+ final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(dictionary,
startOffset, length /* useFullEditDistance */, false, locale);
mLocale = locale;
mMainDictionary = mainDict;
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 4f1759079..b9ec4979d 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -350,7 +350,7 @@ public final class WordComposer {
mPrimaryKeyCodes = new int[MAX_WORD_LENGTH];
final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes,
mInputPointers, mTypedWord.toString(), committedWord, separatorString,
- prevWord);
+ prevWord, mCapitalizedMode);
mInputPointers.reset();
if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD
&& type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) {
@@ -374,6 +374,7 @@ public final class WordComposer {
mTypedWord.setLength(0);
mTypedWord.append(lastComposedWord.mTypedWord);
refreshSize();
+ mCapitalizedMode = lastComposedWord.mCapitalizedMode;
mAutoCorrection = null; // This will be filled by the next call to updateSuggestion.
mIsResumed = true;
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 89d6c9010..907c0cdca 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -81,6 +81,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
public static final int SCRIPT_LATIN = 0;
public static final int SCRIPT_CYRILLIC = 1;
+ public static final int SCRIPT_GREEK = 2;
public static final String SINGLE_QUOTE = "\u0027";
public static final String APOSTROPHE = "\u2019";
private static final TreeMap<String, Integer> mLanguageToScript;
@@ -94,18 +95,23 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
// IMPORTANT: this only contains languages - do not write countries in there.
// Only the language is searched from the map.
mLanguageToScript = CollectionUtils.newTreeMap();
- mLanguageToScript.put("en", SCRIPT_LATIN);
- mLanguageToScript.put("fr", SCRIPT_LATIN);
- mLanguageToScript.put("de", SCRIPT_LATIN);
- mLanguageToScript.put("nl", SCRIPT_LATIN);
mLanguageToScript.put("cs", SCRIPT_LATIN);
+ mLanguageToScript.put("da", SCRIPT_LATIN);
+ mLanguageToScript.put("de", SCRIPT_LATIN);
+ mLanguageToScript.put("el", SCRIPT_GREEK);
+ mLanguageToScript.put("en", SCRIPT_LATIN);
mLanguageToScript.put("es", SCRIPT_LATIN);
- mLanguageToScript.put("it", SCRIPT_LATIN);
+ mLanguageToScript.put("fi", SCRIPT_LATIN);
+ mLanguageToScript.put("fr", SCRIPT_LATIN);
mLanguageToScript.put("hr", SCRIPT_LATIN);
+ mLanguageToScript.put("it", SCRIPT_LATIN);
+ mLanguageToScript.put("lt", SCRIPT_LATIN);
+ mLanguageToScript.put("lv", SCRIPT_LATIN);
+ mLanguageToScript.put("nb", SCRIPT_LATIN);
+ mLanguageToScript.put("nl", SCRIPT_LATIN);
mLanguageToScript.put("pt", SCRIPT_LATIN);
+ mLanguageToScript.put("sl", SCRIPT_LATIN);
mLanguageToScript.put("ru", SCRIPT_CYRILLIC);
- // TODO: Make a persian proximity, and activate the Farsi subtype.
- // mLanguageToScript.put("fa", SCRIPT_PERSIAN);
}
@Override public void onCreate() {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 470943be1..6581978c9 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -143,8 +143,17 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
// All Cyrillic characters are in the 400~52F block. There are some in the upper
// Unicode range, but they are archaic characters that are not used in modern
- // russian and are not used by our dictionary.
+ // Russian and are not used by our dictionary.
return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint);
+ case AndroidSpellCheckerService.SCRIPT_GREEK:
+ // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the
+ // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters.
+ // Our dictionary also contains a few words with 0xF2; it would be best to check
+ // if that's correct, but a Google search does return results for these words so
+ // they are probably okay.
+ return (codePoint >= 0x370 && codePoint <= 0x3FF)
+ || (codePoint >= 0x1F00 && codePoint <= 0x1FFF)
+ || codePoint == 0xF2;
default:
// Should never come here
throw new RuntimeException("Impossible value of script: " + script);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
index 6c0d79c2b..572a826a5 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
@@ -73,6 +73,12 @@ public final class SpellCheckerProximityInfo {
// to spell check has been entered with one of the keyboards above. Also, specifically
// to English, many spelling errors consist of the last vowel of the word being wrong
// because in English vowels tend to merge with each other in pronunciation.
+ /*
+ The Qwerty layout this represents looks like the following:
+ q w e r t y u i o p
+ a s d f g h j k l
+ z x c v b n m
+ */
final static int[] PROXIMITY = {
// Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
// and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
@@ -127,10 +133,13 @@ public final class SpellCheckerProximityInfo {
final private static TreeMap<Integer, Integer> INDICES = CollectionUtils.newTreeMap();
// TODO: The following table is solely based on the keyboard layout. Consult with Russian
// speakers on commonly misspelled words/letters.
- final static int[] PROXIMITY = {
- // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
- // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
- // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
+ /*
+ The Russian layout this represents looks like the following:
+ й ц у к е н г ш щ з х
+ ф ы в а п р о л д ж э
+ я ч с м и т ь б ю
+
+ This gives us the following table:
'й', 'ц', 'ф', 'ы', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'ц', 'й', 'ф', 'ы', 'в', 'у', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'у', 'ц', 'ы', 'в', 'а', 'к', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
@@ -143,7 +152,6 @@ public final class SpellCheckerProximityInfo {
'з', 'щ', 'д', 'ж', 'э', 'х', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'х', 'з', 'ж', 'э', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- // Proximity for row 2. See comment above about size.
'ф', 'й', 'ц', 'ы', 'я', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'ы', 'й', 'ц', 'у', 'ф', 'в', 'я', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'в', 'ц', 'у', 'к', 'ы', 'а', 'я', 'ч', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
@@ -156,7 +164,6 @@ public final class SpellCheckerProximityInfo {
'ж', 'щ', 'з', 'х', 'д', 'э', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'э', 'з', 'х', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- // Proximity for row 3. See comment above about size.
'я', 'ф', 'ы', 'в', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'ч', 'ы', 'в', 'а', 'я', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'с', 'в', 'а', 'п', 'ч', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
@@ -166,6 +173,249 @@ public final class SpellCheckerProximityInfo {
'ь', 'о', 'л', 'д', 'т', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'б', 'л', 'д', 'ж', 'ь', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
'ю', 'д', 'ж', 'э', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ Using the following characters:
+ */
+ private static final int CY_SHORT_I = '\u0439'; // й
+ private static final int CY_TSE = '\u0446'; // ц
+ private static final int CY_U = '\u0443'; // у
+ private static final int CY_KA = '\u043A'; // к
+ private static final int CY_IE = '\u0435'; // е
+ private static final int CY_EN = '\u043D'; // н
+ private static final int CY_GHE = '\u0433'; // г
+ private static final int CY_SHA = '\u0448'; // ш
+ private static final int CY_SHCHA = '\u0449'; // щ
+ private static final int CY_ZE = '\u0437'; // з
+ private static final int CY_HA = '\u0445'; // х
+ private static final int CY_EF = '\u0444'; // ф
+ private static final int CY_YERU = '\u044B'; // ы
+ private static final int CY_VE = '\u0432'; // в
+ private static final int CY_A = '\u0430'; // а
+ private static final int CY_PE = '\u043F'; // п
+ private static final int CY_ER = '\u0440'; // р
+ private static final int CY_O = '\u043E'; // о
+ private static final int CY_EL = '\u043B'; // л
+ private static final int CY_DE = '\u0434'; // д
+ private static final int CY_ZHE = '\u0436'; // ж
+ private static final int CY_E = '\u044D'; // э
+ private static final int CY_YA = '\u044F'; // я
+ private static final int CY_CHE = '\u0447'; // ч
+ private static final int CY_ES = '\u0441'; // с
+ private static final int CY_EM = '\u043C'; // м
+ private static final int CY_I = '\u0438'; // и
+ private static final int CY_TE = '\u0442'; // т
+ private static final int CY_SOFT_SIGN = '\u044C'; // ь
+ private static final int CY_BE = '\u0431'; // б
+ private static final int CY_YU = '\u044E'; // ю
+ final static int[] PROXIMITY = {
+ // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
+ // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
+ // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
+ CY_SHORT_I, CY_TSE, CY_EF, CY_YERU, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_TSE, CY_SHORT_I, CY_EF, CY_YERU, CY_VE, CY_U, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_U, CY_TSE, CY_YERU, CY_VE, CY_A, CY_KA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_KA, CY_U, CY_VE, CY_A, CY_PE, CY_IE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_IE, CY_KA, CY_A, CY_PE, CY_ER, CY_EN, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_EN, CY_IE, CY_PE, CY_ER, CY_O, CY_GHE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_GHE, CY_EN, CY_ER, CY_O, CY_EL, CY_SHA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_SHA, CY_GHE, CY_O, CY_EL, CY_DE, CY_SHCHA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_SHCHA, CY_SHA, CY_EL, CY_DE, CY_ZHE, CY_ZE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_ZE, CY_SHCHA, CY_DE, CY_ZHE, CY_E, CY_HA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_HA, CY_ZE, CY_ZHE, CY_E, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ // Proximity for row 2. See comment above about size.
+ CY_EF, CY_SHORT_I, CY_TSE, CY_YERU, CY_YA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_YERU, CY_SHORT_I, CY_TSE, CY_U, CY_EF, CY_VE, CY_YA, CY_CHE,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_VE, CY_TSE, CY_U, CY_KA, CY_YERU, CY_A, CY_YA, CY_CHE,
+ CY_ES, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_A, CY_U, CY_KA, CY_IE, CY_VE, CY_PE, CY_CHE, CY_ES,
+ CY_EM, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_PE, CY_KA, CY_IE, CY_EN, CY_A, CY_ER, CY_ES, CY_EM,
+ CY_I, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_ER, CY_IE, CY_EN, CY_GHE, CY_PE, CY_O, CY_EM, CY_I,
+ CY_TE, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_O, CY_EN, CY_GHE, CY_SHA, CY_ER, CY_EL, CY_I, CY_TE,
+ CY_SOFT_SIGN, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_EL, CY_GHE, CY_SHA, CY_SHCHA, CY_O, CY_DE, CY_TE, CY_SOFT_SIGN,
+ CY_BE, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_DE, CY_SHA, CY_SHCHA, CY_ZE, CY_EL, CY_ZHE, CY_SOFT_SIGN, CY_BE,
+ CY_YU, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_ZHE, CY_SHCHA, CY_ZE, CY_HA, CY_DE, CY_E, CY_BE, CY_YU,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_E, CY_ZE, CY_HA, CY_YU, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ // Proximity for row 3. See comment above about size.
+ CY_YA, CY_EF, CY_YERU, CY_VE, CY_CHE, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_CHE, CY_YERU, CY_VE, CY_A, CY_YA, CY_ES, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_ES, CY_VE, CY_A, CY_PE, CY_CHE, CY_EM, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_EM, CY_A, CY_PE, CY_ER, CY_ES, CY_I, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_I, CY_PE, CY_ER, CY_O, CY_EM, CY_TE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_TE, CY_ER, CY_O, CY_EL, CY_I, CY_SOFT_SIGN, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_SOFT_SIGN, CY_O, CY_EL, CY_DE, CY_TE, CY_BE, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_BE, CY_EL, CY_DE, CY_ZHE, CY_SOFT_SIGN, CY_YU, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ CY_YU, CY_DE, CY_ZHE, CY_E, CY_BE, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ };
+ static {
+ buildProximityIndices(PROXIMITY, INDICES);
+ }
+ static int getIndexOf(int characterCode) {
+ return computeIndex(characterCode, INDICES);
+ }
+ }
+
+ private static final class Greek {
+ final private static TreeMap<Integer, Integer> INDICES = CollectionUtils.newTreeMap();
+ // TODO: The following table is solely based on the keyboard layout. Consult with Greek
+ // speakers on commonly misspelled words/letters.
+ /*
+ The Greek layout this represents looks like the following:
+ ; ς ε ρ τ υ θ ι ο π
+ α σ δ φ γ η ξ κ λ
+ ζ χ ψ ω β ν μ
+
+ This gives us the following table:
+ 'ς', 'ε', 'α', 'σ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ε', 'ς', 'ρ', 'σ', 'δ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ρ', 'ε', 'τ', 'δ', 'φ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'τ', 'ρ', 'υ', 'φ', 'γ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'υ', 'τ', 'θ', 'γ', 'η', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'θ', 'υ', 'ι', 'η', 'ξ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ι', 'θ', 'ο', 'ξ', 'κ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ο', 'ι', 'π', 'κ', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'π', 'ο', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ 'α', 'ς', 'σ', 'ζ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'σ', 'ς', 'ε', 'α', 'δ', 'ζ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'δ', 'ε', 'ρ', 'σ', 'φ', 'ζ', 'χ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'φ', 'ρ', 'τ', 'δ', 'γ', 'χ', 'ψ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'γ', 'τ', 'υ', 'φ', 'η', 'ψ', 'ω', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'η', 'υ', 'θ', 'γ', 'ξ', 'ω', 'β', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ξ', 'θ', 'ι', 'η', 'κ', 'β', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'κ', 'ι', 'ο', 'ξ', 'λ', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'λ', 'ο', 'π', 'κ', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ 'ζ', 'α', 'σ', 'δ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'χ', 'σ', 'δ', 'φ', 'ζ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ψ', 'δ', 'φ', 'γ', 'χ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ω', 'φ', 'γ', 'η', 'ψ', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'β', 'γ', 'η', 'ξ', 'ω', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'ν', 'η', 'ξ', 'κ', 'β', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ 'μ', 'ξ', 'κ', 'λ', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ Using the following characters:
+ */
+ private static final int GR_FINAL_SIGMA = '\u03C2'; // ς
+ private static final int GR_EPSILON = '\u03B5'; // ε
+ private static final int GR_RHO = '\u03C1'; // ρ
+ private static final int GR_TAU = '\u03C4'; // τ
+ private static final int GR_UPSILON = '\u03C5'; // υ
+ private static final int GR_THETA = '\u03B8'; // θ
+ private static final int GR_IOTA = '\u03B9'; // ι
+ private static final int GR_OMICRON = '\u03BF'; // ο
+ private static final int GR_PI = '\u03C0'; // π
+ private static final int GR_ALPHA = '\u03B1'; // α
+ private static final int GR_SIGMA = '\u03C3'; // σ
+ private static final int GR_DELTA = '\u03B4'; // δ
+ private static final int GR_PHI = '\u03C6'; // φ
+ private static final int GR_GAMMA = '\u03B3'; // γ
+ private static final int GR_ETA = '\u03B7'; // η
+ private static final int GR_XI = '\u03BE'; // ξ
+ private static final int GR_KAPPA = '\u03BA'; // κ
+ private static final int GR_LAMDA = '\u03BB'; // λ
+ private static final int GR_ZETA = '\u03B6'; // ζ
+ private static final int GR_CHI = '\u03C7'; // χ
+ private static final int GR_PSI = '\u03C8'; // ψ
+ private static final int GR_OMEGA = '\u03C9'; // ω
+ private static final int GR_BETA = '\u03B2'; // β
+ private static final int GR_NU = '\u03BD'; // ν
+ private static final int GR_MU = '\u03BC'; // μ
+ final static int[] PROXIMITY = {
+ // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
+ // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
+ // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
+ GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_SIGMA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_EPSILON, GR_FINAL_SIGMA, GR_RHO, GR_SIGMA, GR_DELTA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_RHO, GR_EPSILON, GR_TAU, GR_DELTA, GR_PHI, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_TAU, GR_RHO, GR_UPSILON, GR_PHI, GR_GAMMA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_UPSILON, GR_TAU, GR_THETA, GR_GAMMA, GR_ETA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_THETA, GR_UPSILON, GR_IOTA, GR_ETA, GR_XI, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_IOTA, GR_THETA, GR_OMICRON, GR_XI, GR_KAPPA, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_OMICRON, GR_IOTA, GR_PI, GR_KAPPA, GR_LAMDA, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_PI, GR_OMICRON, GR_LAMDA, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ GR_ALPHA, GR_FINAL_SIGMA, GR_SIGMA, GR_ZETA, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_SIGMA, GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_DELTA, GR_ZETA, GR_CHI, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_DELTA, GR_EPSILON, GR_RHO, GR_SIGMA, GR_PHI, GR_ZETA, GR_CHI, GR_PSI,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_PHI, GR_RHO, GR_TAU, GR_DELTA, GR_GAMMA, GR_CHI, GR_PSI, GR_OMEGA,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_GAMMA, GR_TAU, GR_UPSILON, GR_PHI, GR_ETA, GR_PSI, GR_OMEGA, GR_BETA,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_ETA, GR_UPSILON, GR_THETA, GR_GAMMA, GR_XI, GR_OMEGA, GR_BETA, GR_NU,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_XI, GR_THETA, GR_IOTA, GR_ETA, GR_KAPPA, GR_BETA, GR_NU, GR_MU,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_KAPPA, GR_IOTA, GR_OMICRON, GR_XI, GR_LAMDA, GR_NU, GR_MU, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_LAMDA, GR_OMICRON, GR_PI, GR_KAPPA, GR_MU, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+
+ GR_ZETA, GR_ALPHA, GR_SIGMA, GR_DELTA, GR_CHI, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_CHI, GR_SIGMA, GR_DELTA, GR_PHI, GR_ZETA, GR_PSI, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_PSI, GR_DELTA, GR_PHI, GR_GAMMA, GR_CHI, GR_OMEGA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_OMEGA, GR_PHI, GR_GAMMA, GR_ETA, GR_PSI, GR_BETA, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_BETA, GR_GAMMA, GR_ETA, GR_XI, GR_OMEGA, GR_NU, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_NU, GR_ETA, GR_XI, GR_KAPPA, GR_BETA, GR_MU, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ GR_MU, GR_XI, GR_KAPPA, GR_LAMDA, GR_NU, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
+ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
};
@@ -183,6 +433,8 @@ public final class SpellCheckerProximityInfo {
return Latin.PROXIMITY;
case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
return Cyrillic.PROXIMITY;
+ case AndroidSpellCheckerService.SCRIPT_GREEK:
+ return Greek.PROXIMITY;
default:
throw new RuntimeException("Wrong script supplied: " + script);
}
@@ -194,6 +446,8 @@ public final class SpellCheckerProximityInfo {
return Latin.getIndexOf(codePoint);
case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
return Cyrillic.getIndexOf(codePoint);
+ case AndroidSpellCheckerService.SCRIPT_GREEK:
+ return Greek.getIndexOf(codePoint);
default:
throw new RuntimeException("Wrong script supplied: " + script);
}
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index 7b45ff175..cfba28909 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -133,7 +133,7 @@ import java.util.Map;
// will not have been opened for writing.
if (jsonWriter == null) {
jsonWriter = researchLog.getValidJsonWriterLocked();
- outputLogUnitStart(jsonWriter);
+ outputLogUnitStart(jsonWriter, isIncludingPrivateData);
}
outputLogStatementToLocked(jsonWriter, mLogStatementList.get(i), mValuesList.get(i),
mTimeList.get(i));
@@ -169,11 +169,14 @@ import java.util.Map;
private static final String LOG_UNIT_BEGIN_KEY = "logUnitStart";
private static final String LOG_UNIT_END_KEY = "logUnitEnd";
- private void outputLogUnitStart(final JsonWriter jsonWriter) {
+ private void outputLogUnitStart(final JsonWriter jsonWriter,
+ final boolean isIncludingPrivateData) {
try {
jsonWriter.beginObject();
jsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
- jsonWriter.name(WORD_KEY).value(getWord());
+ if (isIncludingPrivateData) {
+ jsonWriter.name(WORD_KEY).value(getWord());
+ }
jsonWriter.name(EVENT_TYPE_KEY).value(LOG_UNIT_BEGIN_KEY);
jsonWriter.endObject();
} catch (IOException e) {
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index a2356e6a3..5edb46e27 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.research;
+import android.content.Context;
import android.util.JsonWriter;
import android.util.Log;
@@ -23,7 +24,7 @@ import com.android.inputmethod.latin.define.ProductionFlag;
import java.io.BufferedWriter;
import java.io.File;
-import java.io.FileWriter;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@@ -50,6 +51,8 @@ public class ResearchLog {
/* package */ final ScheduledExecutorService mExecutor;
/* package */ final File mFile;
+ private final Context mContext;
+
private JsonWriter mJsonWriter = NULL_JSON_WRITER;
// true if at least one byte of data has been written out to the log file. This must be
// remembered because JsonWriter requires that calls matching calls to beginObject and
@@ -78,12 +81,13 @@ public class ResearchLog {
}
}
- public ResearchLog(final File outputFile) {
+ public ResearchLog(final File outputFile, Context context) {
if (outputFile == null) {
throw new IllegalArgumentException();
}
mExecutor = Executors.newSingleThreadScheduledExecutor();
mFile = outputFile;
+ mContext = context;
}
public synchronized void close(final Runnable onClosed) {
@@ -206,7 +210,9 @@ public class ResearchLog {
public JsonWriter getValidJsonWriterLocked() {
try {
if (mJsonWriter == NULL_JSON_WRITER) {
- mJsonWriter = new JsonWriter(new BufferedWriter(new FileWriter(mFile)));
+ final FileOutputStream fos =
+ mContext.openFileOutput(mFile.getName(), Context.MODE_PRIVATE);
+ mJsonWriter = new JsonWriter(new BufferedWriter(new OutputStreamWriter(fos)));
mJsonWriter.beginArray();
mHasWrittenData = true;
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 4d0808271..79a11fbaf 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -324,11 +324,22 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
sIsLogging = enableLogging;
}
+ private static int sLogFileCounter = 0;
+
private File createLogFile(File filesDir) {
final StringBuilder sb = new StringBuilder();
sb.append(FILENAME_PREFIX).append('-');
sb.append(mUUIDString).append('-');
- sb.append(TIMESTAMP_DATEFORMAT.format(new Date()));
+ sb.append(TIMESTAMP_DATEFORMAT.format(new Date())).append('-');
+ // Sometimes logFiles are created within milliseconds of each other. Append a counter to
+ // separate these.
+ if (sLogFileCounter < Integer.MAX_VALUE) {
+ sLogFileCounter++;
+ } else {
+ // Wrap the counter, in the unlikely event of overflow.
+ sLogFileCounter = 0;
+ }
+ sb.append(sLogFileCounter);
sb.append(FILENAME_SUFFIX);
return new File(filesDir, sb.toString());
}
@@ -374,12 +385,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
return;
}
if (mMainLogBuffer == null) {
- mMainResearchLog = new ResearchLog(createLogFile(mFilesDir));
+ mMainResearchLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME);
mMainLogBuffer = new MainLogBuffer(mMainResearchLog);
mMainLogBuffer.setSuggest(mSuggest);
}
if (mFeedbackLogBuffer == null) {
- mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
+ mFeedbackLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME);
// LogBuffer is one more than FEEDBACK_WORD_BUFFER_SIZE, because it must also hold
// the feedback LogUnit itself.
mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE + 1);
@@ -599,7 +610,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
uploadNow();
}
});
- mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
+ mFeedbackLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME);
}
public void uploadNow() {
@@ -730,6 +741,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
}
+ private static final LogStatement LOGSTATEMENT_UNCOMMIT_CURRENT_LOGUNIT =
+ new LogStatement("UncommitCurrentLogUnit", false, false);
public void uncommitCurrentLogUnit(final String expectedWord,
final boolean dumpCurrentLogUnit) {
// The user has deleted this word and returned to the previous. Check that the word in the
@@ -768,6 +781,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
if (mFeedbackLogBuffer != null) {
mFeedbackLogBuffer.unshiftIn();
}
+ enqueueEvent(LOGSTATEMENT_UNCOMMIT_CURRENT_LOGUNIT);
if (DEBUG) {
Log.d(TAG, "uncommitCurrentLogUnit (dump=" + dumpCurrentLogUnit + ") back to "
+ (mCurrentLogUnit.hasWord() ? ": '" + mCurrentLogUnit.getWord() + "'" : ""));
@@ -1162,7 +1176,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE,
Constants.SUGGESTION_STRIP_COORDINATE);
researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode);
- researchLogger.mStatistics.recordManualSuggestion();
+ researchLogger.mStatistics.recordManualSuggestion(SystemClock.uptimeMillis());
}
/**
@@ -1172,21 +1186,21 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
*/
private static final LogStatement LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION =
new LogStatement("LatinIMEPunctuationSuggestion", false, false, "index", "suggestion",
- "x", "y");
+ "x", "y", "isPrediction");
public static void latinIME_punctuationSuggestion(final int index, final String suggestion,
- final boolean isBatchMode) {
+ final boolean isBatchMode, final boolean isPrediction) {
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION, index, suggestion,
- Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE);
+ Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE,
+ isPrediction);
researchLogger.commitCurrentLogUnitAsWord(suggestion, Long.MAX_VALUE, isBatchMode);
}
/**
* Log a call to LatinIME.sendKeyCodePoint().
*
- * SystemResponse: The IME is simulating a hardware keypress. This happens for numbers; other
- * input typically goes through RichInputConnection.setComposingText() and
- * RichInputConnection.commitText().
+ * SystemResponse: The IME is inserting text into the TextView for numbers, fixed strings, or
+ * some other unusual mechanism.
*/
private static final LogStatement LOGSTATEMENT_LATINIME_SENDKEYCODEPOINT =
new LogStatement("LatinIMESendKeyCodePoint", true, false, "code");
@@ -1200,6 +1214,24 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
/**
+ * Log a call to LatinIME.promotePhantomSpace().
+ *
+ * SystemResponse: The IME is inserting a real space in place of a phantom space.
+ */
+ private static final LogStatement LOGSTATEMENT_LATINIME_PROMOTEPHANTOMSPACE =
+ new LogStatement("LatinIMEPromotPhantomSpace", false, false);
+ public static void latinIME_promotePhantomSpace() {
+ final ResearchLogger researchLogger = getInstance();
+ final LogUnit logUnit;
+ if (researchLogger.mMainLogBuffer == null) {
+ logUnit = researchLogger.mCurrentLogUnit;
+ } else {
+ logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
+ }
+ researchLogger.enqueueEvent(logUnit, LOGSTATEMENT_LATINIME_PROMOTEPHANTOMSPACE);
+ }
+
+ /**
* Log a call to LatinIME.swapSwapperAndSpace().
*
* SystemResponse: A symbol has been swapped with a space character. E.g. punctuation may swap
@@ -1211,7 +1243,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_swapSwapperAndSpace(final CharSequence originalCharacters,
final String charactersAfterSwap) {
final ResearchLogger researchLogger = getInstance();
- final LogUnit logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
+ final LogUnit logUnit;
+ if (researchLogger.mMainLogBuffer == null) {
+ logUnit = null;
+ } else {
+ logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
+ }
if (logUnit != null) {
researchLogger.enqueueEvent(logUnit, LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE,
originalCharacters, charactersAfterSwap);
@@ -1277,20 +1314,27 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
*/
private static final LogStatement LOGSTATEMENT_LATINIME_REVERTCOMMIT =
new LogStatement("LatinIMERevertCommit", true, false, "committedWord",
- "originallyTypedWord");
+ "originallyTypedWord", "separatorString");
public static void latinIME_revertCommit(final String committedWord,
- final String originallyTypedWord, final boolean isBatchMode) {
+ final String originallyTypedWord, final boolean isBatchMode,
+ final String separatorString) {
final ResearchLogger researchLogger = getInstance();
// TODO: Verify that mCurrentLogUnit has been restored and contains the reverted word.
- final LogUnit logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
+ final LogUnit logUnit;
+ if (researchLogger.mMainLogBuffer == null) {
+ logUnit = null;
+ } else {
+ logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
+ }
if (originallyTypedWord.length() > 0 && hasLetters(originallyTypedWord)) {
if (logUnit != null) {
logUnit.setWord(originallyTypedWord);
}
}
researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit,
- LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, originallyTypedWord);
- researchLogger.mStatistics.recordRevertCommit();
+ LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, originallyTypedWord,
+ separatorString);
+ researchLogger.mStatistics.recordRevertCommit(SystemClock.uptimeMillis());
researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE, isBatchMode);
}
@@ -1620,28 +1664,62 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONENDBATCHINPUT, enteredText,
enteredWordPos);
- researchLogger.mStatistics.recordGestureInput(enteredText.length());
+ researchLogger.mStatistics.recordGestureInput(enteredText.length(),
+ SystemClock.uptimeMillis());
}
/**
- * Log a call to LatinIME.handleBackspace().
+ * Log a call to LatinIME.handleBackspace() that is not a batch delete.
+ *
+ * UserInput: The user is deleting one or more characters by hitting the backspace key once.
+ * The covers single character deletes as well as deleting selections.
+ */
+ private static final LogStatement LOGSTATEMENT_LATINIME_HANDLEBACKSPACE =
+ new LogStatement("LatinIMEHandleBackspace", true, false, "numCharacters");
+ public static void latinIME_handleBackspace(final int numCharacters) {
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_HANDLEBACKSPACE, numCharacters);
+ }
+
+ /**
+ * Log a call to LatinIME.handleBackspace() that is a batch delete.
*
* UserInput: The user is deleting a gestured word by hitting the backspace key once.
*/
private static final LogStatement LOGSTATEMENT_LATINIME_HANDLEBACKSPACE_BATCH =
- new LogStatement("LatinIMEHandleBackspaceBatch", true, false, "deletedText");
- public static void latinIME_handleBackspace_batch(final CharSequence deletedText) {
+ new LogStatement("LatinIMEHandleBackspaceBatch", true, false, "deletedText",
+ "numCharacters");
+ public static void latinIME_handleBackspace_batch(final CharSequence deletedText,
+ final int numCharacters) {
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_HANDLEBACKSPACE_BATCH, deletedText,
+ numCharacters);
+ researchLogger.mStatistics.recordGestureDelete(deletedText.length(),
+ SystemClock.uptimeMillis());
+ }
+
+ /**
+ * Log a long interval between user operation.
+ *
+ * UserInput: The user has not done anything for a while.
+ */
+ private static final LogStatement LOGSTATEMENT_ONUSERPAUSE = new LogStatement("OnUserPause",
+ false, false, "intervalInMs");
+ public static void onUserPause(final long interval) {
final ResearchLogger researchLogger = getInstance();
- researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_HANDLEBACKSPACE_BATCH, deletedText);
- researchLogger.mStatistics.recordGestureDelete();
+ researchLogger.enqueueEvent(LOGSTATEMENT_ONUSERPAUSE, interval);
}
- public static void latinIME_handleSeparator() {
- // Reset the saved down event time. For tapping, motion events, etc. before the separator
- // are assigned to the previous LogUnit, and events after the separator are assigned to the
- // next LogUnit. In the case of multitap, this might capture down events corresponding to
- // the next word, however it should not be more than a character or two.
- getInstance().setSavedDownEventTime(SystemClock.uptimeMillis());
+ /**
+ * Record the current time in case the LogUnit is later split.
+ *
+ * If the current logUnitis split, then tapping, motion events, etc. before this time should
+ * be assigned to one LogUnit, and events after this time should go into the following LogUnit.
+ */
+ public static void recordTimeForLogUnitSplit() {
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.setSavedDownEventTime(SystemClock.uptimeMillis());
+ researchLogger.mSavedDownEventTime = Long.MAX_VALUE;
}
/**
diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java
index e9c02c919..a9202651e 100644
--- a/java/src/com/android/inputmethod/research/Statistics.java
+++ b/java/src/com/android/inputmethod/research/Statistics.java
@@ -134,17 +134,9 @@ public class Statistics {
if (DEBUG) {
Log.d(TAG, "recordChar() called");
}
- final long delta = time - mLastTapTime;
if (codePoint == Constants.CODE_DELETE) {
mDeleteKeyCount++;
- if (delta < MIN_DELETION_INTERMISSION) {
- if (mIsLastKeyDeleteKey) {
- mDuringRepeatedDeleteKeysCounter.add(delta);
- } else {
- mBeforeDeleteKeyCounter.add(delta);
- }
- }
- mIsLastKeyDeleteKey = true;
+ recordUserAction(time, true /* isDeletion */);
} else {
mCharCount++;
if (Character.isDigit(codePoint)) {
@@ -156,14 +148,8 @@ public class Statistics {
if (Character.isSpaceChar(codePoint)) {
mSpaceCount++;
}
- if (mIsLastKeyDeleteKey && delta < MIN_DELETION_INTERMISSION) {
- mAfterDeleteKeyCounter.add(delta);
- } else if (!mIsLastKeyDeleteKey && delta < MIN_TYPING_INTERMISSION) {
- mKeyCounter.add(delta);
- }
- mIsLastKeyDeleteKey = false;
+ recordUserAction(time, false /* isDeletion */);
}
- mLastTapTime = time;
}
public void recordWordEntered(final boolean isDictionaryWord) {
@@ -177,9 +163,10 @@ public class Statistics {
mSplitWordsCount++;
}
- public void recordGestureInput(final int numCharsEntered) {
+ public void recordGestureInput(final int numCharsEntered, final long time) {
mGesturesInputCount++;
mGesturesCharsCount += numCharsEntered;
+ recordUserAction(time, false /* isDeletion */);
}
public void setIsEmptyUponStarting(final boolean isEmpty) {
@@ -187,14 +174,43 @@ public class Statistics {
mIsEmptinessStateKnown = true;
}
- public void recordGestureDelete() {
+ public void recordGestureDelete(final int length, final long time) {
mGesturesDeletedCount++;
+ recordUserAction(time, true /* isDeletion */);
}
- public void recordManualSuggestion() {
+
+ public void recordManualSuggestion(final long time) {
mManualSuggestionsCount++;
+ recordUserAction(time, false /* isDeletion */);
}
- public void recordRevertCommit() {
+ public void recordRevertCommit(final long time) {
mRevertCommitsCount++;
+ recordUserAction(time, true /* isDeletion */);
+ }
+
+ private void recordUserAction(final long time, final boolean isDeletion) {
+ final long delta = time - mLastTapTime;
+ if (isDeletion) {
+ if (delta < MIN_DELETION_INTERMISSION) {
+ if (mIsLastKeyDeleteKey) {
+ mDuringRepeatedDeleteKeysCounter.add(delta);
+ } else {
+ mBeforeDeleteKeyCounter.add(delta);
+ }
+ } else {
+ ResearchLogger.onUserPause(delta);
+ }
+ } else {
+ if (mIsLastKeyDeleteKey && delta < MIN_DELETION_INTERMISSION) {
+ mAfterDeleteKeyCounter.add(delta);
+ } else if (!mIsLastKeyDeleteKey && delta < MIN_TYPING_INTERMISSION) {
+ mKeyCounter.add(delta);
+ } else {
+ ResearchLogger.onUserPause(delta);
+ }
+ }
+ mIsLastKeyDeleteKey = isDeletion;
+ mLastTapTime = time;
}
}
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 75f85b120..f2aebd55d 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -66,11 +66,11 @@ LOCAL_SRC_FILES := \
ifeq ($(FLAG_DO_PROFILE), true)
$(warning Making profiling version of native library)
- LOCAL_CFLAGS += -DFLAG_DO_PROFILE -funwind-tables
+ LOCAL_CFLAGS += -DFLAG_DO_PROFILE -funwind-tables -fno-inline
else # FLAG_DO_PROFILE
ifeq ($(FLAG_DBG), true)
$(warning Making debug version of native library)
- LOCAL_CFLAGS += -DFLAG_DBG -funwind-tables
+ LOCAL_CFLAGS += -DFLAG_DBG -funwind-tables -fno-inline
ifeq ($(FLAG_FULL_DBG), true)
$(warning Making full debug version of native library)
LOCAL_CFLAGS += -DFLAG_FULL_DBG
diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
index 4c83c582d..d718290ad 100644
--- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
+++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
@@ -24,12 +24,12 @@
namespace latinime {
-static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object,
- jstring localeJStr, jint maxProximityCharsSize, jint displayWidth, jint displayHeight,
- jint gridWidth, jint gridHeight, jint mostCommonkeyWidth, jintArray proximityChars,
- jint keyCount, jintArray keyXCoordinates, jintArray keyYCoordinates,
- jintArray keyWidths, jintArray keyHeights, jintArray keyCharCodes,
- jfloatArray sweetSpotCenterXs, jfloatArray sweetSpotCenterYs, jfloatArray sweetSpotRadii) {
+static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jclass clazz, jstring localeJStr,
+ jint maxProximityCharsSize, jint displayWidth, jint displayHeight, jint gridWidth,
+ jint gridHeight, jint mostCommonkeyWidth, jintArray proximityChars, jint keyCount,
+ jintArray keyXCoordinates, jintArray keyYCoordinates, jintArray keyWidths,
+ jintArray keyHeights, jintArray keyCharCodes, jfloatArray sweetSpotCenterXs,
+ jfloatArray sweetSpotCenterYs, jfloatArray sweetSpotRadii) {
ProximityInfo *proximityInfo = new ProximityInfo(env, localeJStr, maxProximityCharsSize,
displayWidth, displayHeight, gridWidth, gridHeight, mostCommonkeyWidth, proximityChars,
keyCount, keyXCoordinates, keyYCoordinates, keyWidths, keyHeights, keyCharCodes,
@@ -37,7 +37,7 @@ static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object,
return reinterpret_cast<jlong>(proximityInfo);
}
-static void latinime_Keyboard_release(JNIEnv *env, jobject object, jlong proximityInfo) {
+static void latinime_Keyboard_release(JNIEnv *env, jclass clazz, jlong proximityInfo) {
ProximityInfo *pi = reinterpret_cast<ProximityInfo *>(proximityInfo);
delete pi;
}
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 4e34f98e9..5c8ef7e51 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -42,8 +42,8 @@ class ProximityInfo;
static void releaseDictBuf(const void *dictBuf, const size_t length, const int fd);
-static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jstring sourceDir,
- jlong dictOffset, jlong dictSize, jint maxWordLength, jint maxWords, jint maxPredictions) {
+static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring sourceDir,
+ jlong dictOffset, jlong dictSize) {
PROF_OPEN;
PROF_START(66);
const jsize sourceDirUtf8Length = env->GetStringUTFLength(sourceDir);
@@ -117,18 +117,17 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jstring
releaseDictBuf(dictBuf, 0, 0);
#endif // USE_MMAP_FOR_DICTIONARY
} else {
- dictionary = new Dictionary(dictBuf, static_cast<int>(dictSize), fd, adjust, maxWordLength,
- maxWords, maxPredictions);
+ dictionary = new Dictionary(dictBuf, static_cast<int>(dictSize), fd, adjust);
}
PROF_END(66);
PROF_CLOSE;
return (jlong)dictionary;
}
-static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jlong dict,
+static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jlong dict,
jlong proximityInfo, jlong dicTraverseSession, jintArray xCoordinatesArray,
jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray,
- jintArray inputCodePointsArray, jint arraySize, jint commitPoint, jboolean isGesture,
+ jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jboolean isGesture,
jintArray prevWordCodePointsForBigrams, jboolean useFullEditDistance,
jintArray outputCodePointsArray, jintArray scoresArray, jintArray spaceIndicesArray,
jintArray outputTypesArray) {
@@ -138,20 +137,20 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object,
void *traverseSession = reinterpret_cast<void *>(dicTraverseSession);
// Input values
- int xCoordinates[arraySize];
- int yCoordinates[arraySize];
- int times[arraySize];
- int pointerIds[arraySize];
+ int xCoordinates[inputSize];
+ int yCoordinates[inputSize];
+ int times[inputSize];
+ int pointerIds[inputSize];
const jsize inputCodePointsLength = env->GetArrayLength(inputCodePointsArray);
int inputCodePoints[inputCodePointsLength];
const jsize prevWordCodePointsLength =
prevWordCodePointsForBigrams ? env->GetArrayLength(prevWordCodePointsForBigrams) : 0;
int prevWordCodePointsInternal[prevWordCodePointsLength];
int *prevWordCodePoints = 0;
- env->GetIntArrayRegion(xCoordinatesArray, 0, arraySize, xCoordinates);
- env->GetIntArrayRegion(yCoordinatesArray, 0, arraySize, yCoordinates);
- env->GetIntArrayRegion(timesArray, 0, arraySize, times);
- env->GetIntArrayRegion(pointerIdsArray, 0, arraySize, pointerIds);
+ env->GetIntArrayRegion(xCoordinatesArray, 0, inputSize, xCoordinates);
+ env->GetIntArrayRegion(yCoordinatesArray, 0, inputSize, yCoordinates);
+ env->GetIntArrayRegion(timesArray, 0, inputSize, times);
+ env->GetIntArrayRegion(pointerIdsArray, 0, inputSize, pointerIds);
env->GetIntArrayRegion(inputCodePointsArray, 0, inputCodePointsLength, inputCodePoints);
if (prevWordCodePointsForBigrams) {
env->GetIntArrayRegion(prevWordCodePointsForBigrams, 0, prevWordCodePointsLength,
@@ -160,9 +159,20 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object,
}
// Output values
+ /* By the way, let's check the output array length here to make sure */
const jsize outputCodePointsLength = env->GetArrayLength(outputCodePointsArray);
- int outputCodePoints[outputCodePointsLength];
+ if (outputCodePointsLength != (MAX_WORD_LENGTH * MAX_RESULTS)) {
+ AKLOGE("Invalid outputCodePointsLength: %d", outputCodePointsLength);
+ ASSERT(false);
+ return 0;
+ }
const jsize scoresLength = env->GetArrayLength(scoresArray);
+ if (scoresLength != MAX_RESULTS) {
+ AKLOGE("Invalid scoresLength: %d", scoresLength);
+ ASSERT(false);
+ return 0;
+ }
+ int outputCodePoints[outputCodePointsLength];
int scores[scoresLength];
const jsize spaceIndicesLength = env->GetArrayLength(spaceIndicesArray);
int spaceIndices[spaceIndicesLength];
@@ -174,14 +184,14 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object,
memset(outputTypes, 0, sizeof(outputTypes));
int count;
- if (isGesture || arraySize > 0) {
+ if (isGesture || inputSize > 0) {
count = dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
- times, pointerIds, inputCodePoints, arraySize, prevWordCodePoints,
+ times, pointerIds, inputCodePoints, inputSize, prevWordCodePoints,
prevWordCodePointsLength, commitPoint, isGesture, useFullEditDistance,
outputCodePoints, scores, spaceIndices, outputTypes);
} else {
count = dictionary->getBigrams(prevWordCodePoints, prevWordCodePointsLength,
- inputCodePoints, arraySize, outputCodePoints, scores, outputTypes);
+ inputCodePoints, inputSize, outputCodePoints, scores, outputTypes);
}
// Copy back the output values
@@ -193,7 +203,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object,
return count;
}
-static jint latinime_BinaryDictionary_getFrequency(JNIEnv *env, jobject object, jlong dict,
+static jint latinime_BinaryDictionary_getFrequency(JNIEnv *env, jclass clazz, jlong dict,
jintArray wordArray) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return 0;
@@ -203,7 +213,7 @@ static jint latinime_BinaryDictionary_getFrequency(JNIEnv *env, jobject object,
return dictionary->getFrequency(codePoints, codePointLength);
}
-static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jobject object, jlong dict,
+static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jclass clazz, jlong dict,
jintArray wordArray1, jintArray wordArray2) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return (jboolean) false;
@@ -216,7 +226,7 @@ static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jobject obj
return dictionary->isValidBigram(codePoints1, codePointLength1, codePoints2, codePointLength2);
}
-static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject object,
+static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jclass clazz,
jintArray before, jintArray after, jint score) {
jsize beforeLength = env->GetArrayLength(before);
jsize afterLength = env->GetArrayLength(after);
@@ -228,7 +238,7 @@ static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject
afterCodePoints, afterLength, score);
}
-static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jobject object, jintArray before,
+static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jclass clazz, jintArray before,
jintArray after) {
jsize beforeLength = env->GetArrayLength(before);
jsize afterLength = env->GetArrayLength(after);
@@ -240,7 +250,7 @@ static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jobject object,
afterCodePoints, afterLength);
}
-static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jlong dict) {
+static void latinime_BinaryDictionary_close(JNIEnv *env, jclass clazz, jlong dict) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return;
const void *dictBuf = dictionary->getDict();
@@ -270,7 +280,7 @@ static void releaseDictBuf(const void *dictBuf, const size_t length, const int f
}
static JNINativeMethod sMethods[] = {
- {"openNative", "(Ljava/lang/String;JJIII)J",
+ {"openNative", "(Ljava/lang/String;JJ)J",
reinterpret_cast<void *>(latinime_BinaryDictionary_open)},
{"closeNative", "(J)V", reinterpret_cast<void *>(latinime_BinaryDictionary_close)},
{"getSuggestionsNative", "(JJJ[I[I[I[I[IIIZ[IZ[I[I[I[I)I",
diff --git a/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp b/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
index 73ac84cd7..9b39245b9 100644
--- a/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
+++ b/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
@@ -24,12 +24,12 @@
namespace latinime {
class Dictionary;
-static jlong latinime_setDicTraverseSession(JNIEnv *env, jobject object, jstring localeJStr) {
+static jlong latinime_setDicTraverseSession(JNIEnv *env, jclass clazz, jstring localeJStr) {
void *traverseSession = DicTraverseWrapper::getDicTraverseSession(env, localeJStr);
return reinterpret_cast<jlong>(traverseSession);
}
-static void latinime_initDicTraverseSession(JNIEnv *env, jobject object, jlong traverseSession,
+static void latinime_initDicTraverseSession(JNIEnv *env, jclass clazz, jlong traverseSession,
jlong dictionary, jintArray previousWord, jint previousWordLength) {
void *ts = reinterpret_cast<void *>(traverseSession);
Dictionary *dict = reinterpret_cast<Dictionary *>(dictionary);
@@ -42,7 +42,7 @@ static void latinime_initDicTraverseSession(JNIEnv *env, jobject object, jlong t
DicTraverseWrapper::initDicTraverseSession(ts, dict, prevWord, previousWordLength);
}
-static void latinime_releaseDicTraverseSession(JNIEnv *env, jobject object, jlong traverseSession) {
+static void latinime_releaseDicTraverseSession(JNIEnv *env, jclass clazz, jlong traverseSession) {
void *ts = reinterpret_cast<void *>(traverseSession);
DicTraverseWrapper::releaseDicTraverseSession(ts);
}
diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp
index e62ae6fd9..44dc75e9c 100644
--- a/native/jni/src/bigram_dictionary.cpp
+++ b/native/jni/src/bigram_dictionary.cpp
@@ -26,8 +26,7 @@
namespace latinime {
-BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength, int maxPredictions)
- : DICT(dict), MAX_WORD_LENGTH(maxWordLength), MAX_PREDICTIONS(maxPredictions) {
+BigramDictionary::BigramDictionary(const uint8_t *const streamStart) : DICT_ROOT(streamStart) {
if (DEBUG_DICT) {
AKLOGI("BigramDictionary - constructor");
}
@@ -36,7 +35,7 @@ BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength,
BigramDictionary::~BigramDictionary() {
}
-bool BigramDictionary::addWordBigram(int *word, int length, int frequency, int *bigramFreq,
+void BigramDictionary::addWordBigram(int *word, int length, int frequency, int *bigramFreq,
int *bigramCodePoints, int *outputTypes) const {
word[length] = 0;
if (DEBUG_DICT) {
@@ -49,7 +48,7 @@ bool BigramDictionary::addWordBigram(int *word, int length, int frequency, int *
// Find the right insertion point
int insertAt = 0;
- while (insertAt < MAX_PREDICTIONS) {
+ while (insertAt < MAX_RESULTS) {
if (frequency > bigramFreq[insertAt] || (bigramFreq[insertAt] == frequency
&& length < Dictionary::wideStrLen(
bigramCodePoints + insertAt * MAX_WORD_LENGTH))) {
@@ -58,35 +57,34 @@ bool BigramDictionary::addWordBigram(int *word, int length, int frequency, int *
insertAt++;
}
if (DEBUG_DICT) {
- AKLOGI("Bigram: InsertAt -> %d MAX_PREDICTIONS: %d", insertAt, MAX_PREDICTIONS);
+ AKLOGI("Bigram: InsertAt -> %d MAX_RESULTS: %d", insertAt, MAX_RESULTS);
}
- if (insertAt < MAX_PREDICTIONS) {
- memmove(bigramFreq + (insertAt + 1),
- bigramFreq + insertAt,
- (MAX_PREDICTIONS - insertAt - 1) * sizeof(bigramFreq[0]));
- bigramFreq[insertAt] = frequency;
- outputTypes[insertAt] = Dictionary::KIND_PREDICTION;
- memmove(bigramCodePoints + (insertAt + 1) * MAX_WORD_LENGTH,
- bigramCodePoints + insertAt * MAX_WORD_LENGTH,
- (MAX_PREDICTIONS - insertAt - 1) * sizeof(bigramCodePoints[0]) * MAX_WORD_LENGTH);
- int *dest = bigramCodePoints + insertAt * MAX_WORD_LENGTH;
- while (length--) {
- *dest++ = *word++;
- }
- *dest = 0; // NULL terminate
- if (DEBUG_DICT) {
- AKLOGI("Bigram: Added word at %d", insertAt);
- }
- return true;
+ if (insertAt >= MAX_RESULTS) {
+ return;
+ }
+ memmove(bigramFreq + (insertAt + 1),
+ bigramFreq + insertAt,
+ (MAX_RESULTS - insertAt - 1) * sizeof(bigramFreq[0]));
+ bigramFreq[insertAt] = frequency;
+ outputTypes[insertAt] = Dictionary::KIND_PREDICTION;
+ memmove(bigramCodePoints + (insertAt + 1) * MAX_WORD_LENGTH,
+ bigramCodePoints + insertAt * MAX_WORD_LENGTH,
+ (MAX_RESULTS - insertAt - 1) * sizeof(bigramCodePoints[0]) * MAX_WORD_LENGTH);
+ int *dest = bigramCodePoints + insertAt * MAX_WORD_LENGTH;
+ while (length--) {
+ *dest++ = *word++;
+ }
+ *dest = 0; // NULL terminate
+ if (DEBUG_DICT) {
+ AKLOGI("Bigram: Added word at %d", insertAt);
}
- return false;
}
/* Parameters :
* prevWord: the word before, the one for which we need to look up bigrams.
* prevWordLength: its length.
- * inputCodes: what user typed, in the same format as for UnigramDictionary::getSuggestions.
- * codesSize: the size of the codes array.
+ * inputCodePoints: what user typed, in the same format as for UnigramDictionary::getSuggestions.
+ * inputSize: the size of the codes array.
* bigramCodePoints: an array for output, at the same format as outwords for getSuggestions.
* bigramFreq: an array to output frequencies.
* outputTypes: an array to output types.
@@ -98,12 +96,12 @@ bool BigramDictionary::addWordBigram(int *word, int length, int frequency, int *
* and the bigrams are used to boost unigram result scores, it makes little sense to
* reduce their scope to the ones that match the first letter.
*/
-int BigramDictionary::getBigrams(const int *prevWord, int prevWordLength, int *inputCodes,
- int codesSize, int *bigramCodePoints, int *bigramFreq, int *outputTypes) const {
+int BigramDictionary::getBigrams(const int *prevWord, int prevWordLength, int *inputCodePoints,
+ int inputSize, int *bigramCodePoints, int *bigramFreq, int *outputTypes) const {
// TODO: remove unused arguments, and refrain from storing stuff in members of this class
// TODO: have "in" arguments before "out" ones, and make out args explicit in the name
- const uint8_t *const root = DICT;
+ const uint8_t *const root = DICT_ROOT;
int pos = getBigramListPositionForWord(prevWord, prevWordLength,
false /* forceLowerCaseSearch */);
// getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams
@@ -125,8 +123,8 @@ int BigramDictionary::getBigrams(const int *prevWord, int prevWordLength, int *i
const int length = BinaryFormat::getWordAtAddress(root, bigramPos, MAX_WORD_LENGTH,
bigramBuffer, &unigramFreq);
- // codesSize == 0 means we are trying to find bigram predictions.
- if (codesSize < 1 || checkFirstCharacter(bigramBuffer, inputCodes)) {
+ // inputSize == 0 means we are trying to find bigram predictions.
+ if (inputSize < 1 || checkFirstCharacter(bigramBuffer, inputCodePoints)) {
const int bigramFreqTemp = BinaryFormat::MASK_ATTRIBUTE_FREQUENCY & bigramFlags;
// Due to space constraints, the frequency for bigrams is approximate - the lower the
// unigram frequency, the worse the precision. The theoritical maximum error in
@@ -135,13 +133,12 @@ int BigramDictionary::getBigrams(const int *prevWord, int prevWordLength, int *i
// here, but it can't get too bad.
const int frequency =
BinaryFormat::computeFrequencyForBigram(unigramFreq, bigramFreqTemp);
- if (addWordBigram(bigramBuffer, length, frequency, bigramFreq, bigramCodePoints,
- outputTypes)) {
- ++bigramCount;
- }
+ addWordBigram(bigramBuffer, length, frequency, bigramFreq, bigramCodePoints,
+ outputTypes);
+ ++bigramCount;
}
} while (BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags);
- return bigramCount;
+ return min(bigramCount, MAX_RESULTS);
}
// Returns a pointer to the start of the bigram list.
@@ -149,7 +146,7 @@ int BigramDictionary::getBigrams(const int *prevWord, int prevWordLength, int *i
int BigramDictionary::getBigramListPositionForWord(const int *prevWord, const int prevWordLength,
const bool forceLowerCaseSearch) const {
if (0 >= prevWordLength) return 0;
- const uint8_t *const root = DICT;
+ const uint8_t *const root = DICT_ROOT;
int pos = BinaryFormat::getTerminalPosition(root, prevWord, prevWordLength,
forceLowerCaseSearch);
@@ -170,7 +167,7 @@ int BigramDictionary::getBigramListPositionForWord(const int *prevWord, const in
void BigramDictionary::fillBigramAddressToFrequencyMapAndFilter(const int *prevWord,
const int prevWordLength, std::map<int, int> *map, uint8_t *filter) const {
memset(filter, 0, BIGRAM_FILTER_BYTE_SIZE);
- const uint8_t *const root = DICT;
+ const uint8_t *const root = DICT_ROOT;
int pos = getBigramListPositionForWord(prevWord, prevWordLength,
false /* forceLowerCaseSearch */);
if (0 == pos) {
@@ -191,17 +188,17 @@ void BigramDictionary::fillBigramAddressToFrequencyMapAndFilter(const int *prevW
} while (0 != (BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags));
}
-bool BigramDictionary::checkFirstCharacter(int *word, int *inputCodes) const {
+bool BigramDictionary::checkFirstCharacter(int *word, int *inputCodePoints) const {
// Checks whether this word starts with same character or neighboring characters of
// what user typed.
int maxAlt = MAX_ALTERNATIVES;
- const int firstBaseChar = toBaseLowerCase(*word);
+ const int firstBaseLowerCodePoint = toBaseLowerCase(*word);
while (maxAlt > 0) {
- if (toBaseLowerCase(*inputCodes) == firstBaseChar) {
+ if (toBaseLowerCase(*inputCodePoints) == firstBaseLowerCodePoint) {
return true;
}
- inputCodes++;
+ inputCodePoints++;
maxAlt--;
}
return false;
@@ -209,7 +206,7 @@ bool BigramDictionary::checkFirstCharacter(int *word, int *inputCodes) const {
bool BigramDictionary::isValidBigram(const int *word1, int length1, const int *word2,
int length2) const {
- const uint8_t *const root = DICT;
+ const uint8_t *const root = DICT_ROOT;
int pos = getBigramListPositionForWord(word1, length1, false /* forceLowerCaseSearch */);
// getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams
if (0 == pos) return false;
diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h
index 150192de2..2ce6c1d0d 100644
--- a/native/jni/src/bigram_dictionary.h
+++ b/native/jni/src/bigram_dictionary.h
@@ -26,8 +26,8 @@ namespace latinime {
class BigramDictionary {
public:
- BigramDictionary(const unsigned char *dict, int maxWordLength, int maxPredictions);
- int getBigrams(const int *word, int length, int *inputCodes, int codesSize, int *outWords,
+ BigramDictionary(const uint8_t *const streamStart);
+ int getBigrams(const int *word, int length, int *inputCodePoints, int inputSize, int *outWords,
int *frequencies, int *outputTypes) const;
void fillBigramAddressToFrequencyMapAndFilter(const int *prevWord, const int prevWordLength,
std::map<int, int> *map, uint8_t *filter) const;
@@ -35,20 +35,13 @@ class BigramDictionary {
~BigramDictionary();
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BigramDictionary);
- bool addWordBigram(int *word, int length, int frequency, int *bigramFreq, int *bigramCodePoints,
+ void addWordBigram(int *word, int length, int frequency, int *bigramFreq, int *bigramCodePoints,
int *outputTypes) const;
- int getBigramAddress(int *pos, bool advance);
- int getBigramFreq(int *pos);
- void searchForTerminalNode(int addressLookingFor, int frequency);
- bool getFirstBitOfByte(int *pos) { return (DICT[*pos] & 0x80) > 0; }
- bool getSecondBitOfByte(int *pos) { return (DICT[*pos] & 0x40) > 0; }
- bool checkFirstCharacter(int *word, int *inputCodes) const;
+ bool checkFirstCharacter(int *word, int *inputCodePoints) const;
int getBigramListPositionForWord(const int *prevWord, const int prevWordLength,
const bool forceLowerCaseSearch) const;
- const unsigned char *DICT;
- const int MAX_WORD_LENGTH;
- const int MAX_PREDICTIONS;
+ const uint8_t *const DICT_ROOT;
// TODO: Re-implement proximity correction for bigram correction
static const int MAX_ALTERNATIVES = 1;
};
diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp
index a0256ee40..e892c8591 100644
--- a/native/jni/src/correction.cpp
+++ b/native/jni/src/correction.cpp
@@ -16,10 +16,13 @@
#define LOG_TAG "LatinIME: correction.cpp"
+#include <cmath>
+
#include "char_utils.h"
#include "correction.h"
#include "defines.h"
#include "proximity_info_state.h"
+#include "suggest_utils.h"
namespace latinime {
@@ -30,7 +33,7 @@ class ProximityInfo;
/////////////////////////////
inline static void initEditDistance(int *editDistanceTable) {
- for (int i = 0; i <= MAX_WORD_LENGTH_INTERNAL; ++i) {
+ for (int i = 0; i <= MAX_WORD_LENGTH; ++i) {
editDistanceTable[i] = i;
}
}
@@ -77,7 +80,7 @@ void Correction::initCorrection(const ProximityInfo *pi, const int inputSize, co
mMaxDepth = maxDepth;
mMaxEditDistance = mInputSize < 5 ? 2 : mInputSize / 2;
// TODO: This is not supposed to be required. Check what's going wrong with
- // editDistance[0 ~ MAX_WORD_LENGTH_INTERNAL]
+ // editDistance[0 ~ MAX_WORD_LENGTH]
initEditDistance(mEditDistanceTable);
}
@@ -671,27 +674,9 @@ inline static bool isUpperCase(unsigned short c) {
if (i < adjustedProximityMatchedCount) {
multiplyIntCapped(typedLetterMultiplier, &finalFreq);
}
- if (squaredDistance >= 0) {
- // Promote or demote the score according to the distance from the sweet spot
- static const float A = ZERO_DISTANCE_PROMOTION_RATE / 100.0f;
- static const float B = 1.0f;
- static const float C = 0.5f;
- static const float MIN = 0.3f;
- static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS;
- static const float R2 = HALF_SCORE_SQUARED_RADIUS;
- const float x = static_cast<float>(squaredDistance)
- / ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR;
- const float factor = max((x < R1)
- ? (A * (R1 - x) + B * x) / R1
- : (B * (R2 - x) + C * (x - R1)) / (R2 - R1), MIN);
- // factor is a piecewise linear function like:
- // A -_ .
- // ^-_ .
- // B \ .
- // \_ .
- // C ------------.
- // .
- // 0 R1 R2 .
+ const float factor =
+ SuggestUtils::getDistanceScalingFactor(static_cast<float>(squaredDistance));
+ if (factor > 0.0f) {
multiplyRate((int)(factor * 100.0f), &finalFreq);
} else if (squaredDistance == PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO) {
multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq);
diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h
index 8c477716a..89e300d75 100644
--- a/native/jni/src/correction.h
+++ b/native/jni/src/correction.h
@@ -57,7 +57,7 @@ class Correction {
// Non virtual inline destructor -- never inherit this class
~Correction() {}
void resetCorrection();
- void initCorrection(const ProximityInfo *pi, const int inputSize, const int maxWordLength);
+ void initCorrection(const ProximityInfo *pi, const int inputSize, const int maxDepth);
void initCorrectionState(const int rootPos, const int childCount, const bool traverseAll);
// TODO: remove
@@ -237,14 +237,14 @@ class Correction {
int mTotalTraverseCount;
// The following arrays are state buffer.
- int mWord[MAX_WORD_LENGTH_INTERNAL];
- int mDistances[MAX_WORD_LENGTH_INTERNAL];
+ int mWord[MAX_WORD_LENGTH];
+ int mDistances[MAX_WORD_LENGTH];
// Edit distance calculation requires a buffer with (N+1)^2 length for the input length N.
// Caveat: Do not create multiple tables per thread as this table eats up RAM a lot.
- int mEditDistanceTable[(MAX_WORD_LENGTH_INTERNAL + 1) * (MAX_WORD_LENGTH_INTERNAL + 1)];
+ int mEditDistanceTable[(MAX_WORD_LENGTH + 1) * (MAX_WORD_LENGTH + 1)];
- CorrectionState mCorrectionStates[MAX_WORD_LENGTH_INTERNAL];
+ CorrectionState mCorrectionStates[MAX_WORD_LENGTH];
// The following member variables are being used as cache values of the correction state.
bool mNeedsToTraverseAllNodes;
@@ -336,7 +336,7 @@ inline Correction::CorrectionType Correction::processUnrelatedCorrectionType() {
AK_FORCE_INLINE static void calcEditDistanceOneStep(int *editDistanceTable, const int *input,
const int inputSize, const int *output, const int outputLength) {
- // TODO: Make sure that editDistance[0 ~ MAX_WORD_LENGTH_INTERNAL] is not touched.
+ // TODO: Make sure that editDistance[0 ~ MAX_WORD_LENGTH] is not touched.
// Let dp[i][j] be editDistanceTable[i * (inputSize + 1) + j].
// Assuming that dp[0][0] ... dp[outputLength - 1][inputSize] are already calculated,
// and calculate dp[ouputLength][0] ... dp[outputLength][inputSize].
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 96abfe8d4..4d5a2b261 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -23,19 +23,25 @@
#define AK_FORCE_INLINE inline
#endif // __GNUC__
-// This must be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java
-#define MAX_WORD_LENGTH_INTERNAL 48
+#if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG)
+#undef AK_FORCE_INLINE
+#define AK_FORCE_INLINE inline
+#endif // defined(FLAG_DO_PROFILE) || defined(FLAG_DBG)
+
+// Must be identical to Constants.Dictionary.MAX_WORD_LENGTH in Java
+#define MAX_WORD_LENGTH 48
+// Must be identical to BinaryDictionary.MAX_RESULTS in Java
+#define MAX_RESULTS 18
#if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG)
#include <android/log.h>
#ifndef LOG_TAG
#define LOG_TAG "LatinIME: "
-#endif
+#endif // LOG_TAG
#define AKLOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__)
#define AKLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__)
-#define DUMP_RESULT(words, frequencies, maxWordCount, maxWordLength) do { \
- dumpResult(words, frequencies, maxWordCount, maxWordLength); } while (0)
+#define DUMP_RESULT(words, frequencies) do { dumpResult(words, frequencies); } while (0)
#define DUMP_WORD(word, length) do { dumpWord(word, length); } while (0)
#define INTS_TO_CHARS(input, length, output) do { \
intArrayToCharArray(input, length, output); } while (0)
@@ -45,7 +51,7 @@ AK_FORCE_INLINE static int intArrayToCharArray(const int *source, const int sour
char *dest) {
int si = 0;
int di = 0;
- while (si < sourceSize && di < MAX_WORD_LENGTH_INTERNAL - 1 && 0 != source[si]) {
+ while (si < sourceSize && di < MAX_WORD_LENGTH - 1 && 0 != source[si]) {
const int codePoint = source[si++];
if (codePoint < 0x7F) {
dest[di++] = codePoint;
@@ -71,11 +77,10 @@ static inline void dumpWordInfo(const int *word, const int length, const int ran
}
}
-static inline void dumpResult(const int *outWords, const int *frequencies, const int maxWordCounts,
- const int maxWordLength) {
+static inline void dumpResult(const int *outWords, const int *frequencies) {
AKLOGI("--- DUMP RESULT ---------");
- for (int i = 0; i < maxWordCounts; ++i) {
- dumpWordInfo(&outWords[i * maxWordLength], maxWordLength, i, frequencies[i]);
+ for (int i = 0; i < MAX_RESULTS; ++i) {
+ dumpWordInfo(&outWords[i * MAX_WORD_LENGTH], MAX_WORD_LENGTH, i, frequencies[i]);
}
AKLOGI("-------------------------");
}
@@ -110,23 +115,23 @@ static inline void showStackTrace() {
}
free(strs);
}
-#else
+#else // __ANDROID__
#include <cassert>
#define DO_ASSERT_TEST
#define ASSERT(success) assert(success)
#define SHOW_STACK_TRACE
-#endif
+#endif // __ANDROID__
-#else
+#else // defined(FLAG_DO_PROFILE) || defined(FLAG_DBG)
#define AKLOGE(fmt, ...)
#define AKLOGI(fmt, ...)
-#define DUMP_RESULT(words, frequencies, maxWordCount, maxWordLength)
+#define DUMP_RESULT(words, frequencies)
#define DUMP_WORD(word, length)
#undef DO_ASSERT_TEST
#define ASSERT(success)
#define SHOW_STACK_TRACE
#define INTS_TO_CHARS(input, length, output)
-#endif
+#endif // defined(FLAG_DO_PROFILE) || defined(FLAG_DBG)
#ifdef FLAG_DO_PROFILE
// Profiler
@@ -311,7 +316,7 @@ static inline void prof_out(void) {
#define TWO_WORDS_CAPITALIZED_DEMOTION_RATE 50
#define TWO_WORDS_CORRECTION_DEMOTION_BASE 80
#define TWO_WORDS_PLUS_OTHER_ERROR_CORRECTION_DEMOTION_DIVIDER 1
-#define ZERO_DISTANCE_PROMOTION_RATE 110
+#define ZERO_DISTANCE_PROMOTION_RATE 110.0f
#define NEUTRAL_SCORE_SQUARED_RADIUS 8.0f
#define HALF_SCORE_SQUARED_RADIUS 32.0f
#define MAX_FREQ 255
@@ -347,14 +352,8 @@ static inline void prof_out(void) {
#define SUPPRESS_SHORT_MULTIPLE_WORDS_THRESHOLD_FREQ (MAX_FREQ * 58 / 100)
#define MAX_DEPTH_MULTIPLIER 3
-
#define FIRST_WORD_INDEX 0
-#define MAX_SPACES_INTERNAL 16
-
-// TODO: Change this to MAX_WORDS, remove MAX_WORDS in Java, and stop getting it from Java
-#define MAX_WORDS_INTERNAL 18
-
// Max Distance between point to key
#define MAX_POINT_TO_KEY_LENGTH 10000000
diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp
index 167b36f11..2be1f4f39 100644
--- a/native/jni/src/dictionary.cpp
+++ b/native/jni/src/dictionary.cpp
@@ -28,22 +28,13 @@
namespace latinime {
-Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int maxWordLength,
- int maxWords, int maxPredictions)
+Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust)
: mDict(static_cast<unsigned char *>(dict)),
mOffsetDict((static_cast<unsigned char *>(dict)) + BinaryFormat::getHeaderSize(mDict)),
mDictSize(dictSize), mMmapFd(mmapFd), mDictBufAdjust(dictBufAdjust),
- mUnigramDictionary(new UnigramDictionary(mOffsetDict, maxWordLength, maxWords,
- BinaryFormat::getFlags(mDict))),
- mBigramDictionary(new BigramDictionary(mOffsetDict, maxWordLength, maxPredictions)),
- mGestureSuggest(new GestureSuggest(maxWordLength, maxWords)) {
- if (DEBUG_DICT) {
- if (MAX_WORD_LENGTH_INTERNAL < maxWordLength) {
- AKLOGI("Max word length (%d) is greater than %d",
- maxWordLength, MAX_WORD_LENGTH_INTERNAL);
- AKLOGI("IN NATIVE SUGGEST Version: %d", (mDict[0] & 0xFF));
- }
- }
+ mUnigramDictionary(new UnigramDictionary(mOffsetDict, BinaryFormat::getFlags(mDict))),
+ mBigramDictionary(new BigramDictionary(mOffsetDict)),
+ mGestureSuggest(new GestureSuggest()) {
}
Dictionary::~Dictionary() {
@@ -53,38 +44,38 @@ Dictionary::~Dictionary() {
}
int Dictionary::getSuggestions(ProximityInfo *proximityInfo, void *traverseSession,
- int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *codes,
- int codesSize, int *prevWordChars, int prevWordLength, int commitPoint, bool isGesture,
+ int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
+ int inputSize, int *prevWordCodePoints, int prevWordLength, int commitPoint, bool isGesture,
bool useFullEditDistance, int *outWords, int *frequencies, int *spaceIndices,
int *outputTypes) const {
int result = 0;
if (isGesture) {
DicTraverseWrapper::initDicTraverseSession(
- traverseSession, this, prevWordChars, prevWordLength);
- result = mGestureSuggest->getSuggestions(proximityInfo, traverseSession,
- xcoordinates, ycoordinates, times, pointerIds, codes, codesSize, commitPoint,
- outWords, frequencies, spaceIndices, outputTypes);
+ traverseSession, this, prevWordCodePoints, prevWordLength);
+ result = mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
+ ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint, outWords,
+ frequencies, spaceIndices, outputTypes);
if (DEBUG_DICT) {
- DUMP_RESULT(outWords, frequencies, 18 /* MAX_WORDS */, MAX_WORD_LENGTH_INTERNAL);
+ DUMP_RESULT(outWords, frequencies);
}
return result;
} else {
std::map<int, int> bigramMap;
uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE];
- mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordChars,
+ mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordCodePoints,
prevWordLength, &bigramMap, bigramFilter);
- result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates,
- ycoordinates, codes, codesSize, &bigramMap, bigramFilter,
- useFullEditDistance, outWords, frequencies, outputTypes);
+ result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, ycoordinates,
+ inputCodePoints, inputSize, &bigramMap, bigramFilter, useFullEditDistance, outWords,
+ frequencies, outputTypes);
return result;
}
}
-int Dictionary::getBigrams(const int *word, int length, int *codes, int codesSize,
+int Dictionary::getBigrams(const int *word, int length, int *inputCodePoints, int inputSize,
int *outWords, int *frequencies, int *outputTypes) const {
if (length <= 0) return 0;
- return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies,
- outputTypes);
+ return mBigramDictionary->getBigrams(word, length, inputCodePoints, inputSize, outWords,
+ frequencies, outputTypes);
}
int Dictionary::getFrequency(const int *word, int length) const {
diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h
index 26edc4f2f..121cf058d 100644
--- a/native/jni/src/dictionary.h
+++ b/native/jni/src/dictionary.h
@@ -41,16 +41,15 @@ class Dictionary {
const static int KIND_SHORTCUT = 7; // A shortcut
const static int KIND_PREDICTION = 8; // A prediction (== a suggestion with no input)
- Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int maxWordLength,
- int maxWords, int maxPredictions);
+ Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust);
int getSuggestions(ProximityInfo *proximityInfo, void *traverseSession, int *xcoordinates,
- int *ycoordinates, int *times, int *pointerIds, int *codes, int codesSize,
- int *prevWordChars, int prevWordLength, int commitPoint, bool isGesture,
+ int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints, int inputSize,
+ int *prevWordCodePoints, int prevWordLength, int commitPoint, bool isGesture,
bool useFullEditDistance, int *outWords, int *frequencies, int *spaceIndices,
int *outputTypes) const;
- int getBigrams(const int *word, int length, int *codes, int codesSize, int *outWords,
+ int getBigrams(const int *word, int length, int *inputCodePoints, int inputSize, int *outWords,
int *frequencies, int *outputTypes) const;
int getFrequency(const int *word, int length) const;
diff --git a/native/jni/src/geometry_utils.h b/native/jni/src/geometry_utils.h
index 4060a7bd3..4bff80f15 100644
--- a/native/jni/src/geometry_utils.h
+++ b/native/jni/src/geometry_utils.h
@@ -21,8 +21,6 @@
#include "defines.h"
-#define DEBUG_DECODER false
-
#define M_PI_F 3.14159265f
#define ROUND_FLOAT_10000(f) ((f) < 1000.0f && (f) > 0.001f) \
? (floorf((f) * 10000.0f) / 10000.0f) : (f)
@@ -36,19 +34,8 @@ static inline float getSquaredDistanceFloat(const float x1, const float y1, cons
return SQUARE_FLOAT(x1 - x2) + SQUARE_FLOAT(y1 - y2);
}
-static inline float getNormalizedSquaredDistanceFloat(const float x1, const float y1,
- const float x2, const float y2, const float scale) {
- return getSquaredDistanceFloat(x1, y1, x2, y2) / SQUARE_FLOAT(scale);
-}
-
-static inline float getDistanceFloat(const float x1, const float y1, const float x2,
- const float y2) {
- return hypotf(x1 - x2, y1 - y2);
-}
-
static AK_FORCE_INLINE int getDistanceInt(const int x1, const int y1, const int x2, const int y2) {
- return static_cast<int>(getDistanceFloat(static_cast<float>(x1), static_cast<float>(y1),
- static_cast<float>(x2), static_cast<float>(y2)));
+ return static_cast<int>(hypotf(static_cast<float>(x1 - x2), static_cast<float>(y1 - y2)));
}
static AK_FORCE_INLINE float getAngle(const int x1, const int y1, const int x2, const int y2) {
diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp
index 8ad9c77dc..9b99554d6 100644
--- a/native/jni/src/proximity_info.cpp
+++ b/native/jni/src/proximity_info.cpp
@@ -144,7 +144,7 @@ float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG(
const float touchX = static_cast<float>(x);
const float touchY = static_cast<float>(y);
const float keyWidth = static_cast<float>(getMostCommonKeyWidth());
- return getNormalizedSquaredDistanceFloat(centerX, centerY, touchX, touchY, keyWidth);
+ return getSquaredDistanceFloat(centerX, centerY, touchX, touchY) / SQUARE_FLOAT(keyWidth);
}
int ProximityInfo::squaredDistanceToEdge(const int keyId, const int x, const int y) const {
diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp
index 5362d69f0..aa029297e 100644
--- a/native/jni/src/proximity_info_state.cpp
+++ b/native/jni/src/proximity_info_state.cpp
@@ -20,6 +20,7 @@
#define LOG_TAG "LatinIME: proximity_info_state.cpp"
#include "defines.h"
+#include "geometry_utils.h"
#include "proximity_info.h"
#include "proximity_info_state.h"
@@ -100,7 +101,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
mTimes.clear();
mInputIndice.clear();
mLengthCache.clear();
- mDistanceCache.clear();
+ mDistanceCache_G.clear();
mNearKeysVector.clear();
mSearchKeysVector.clear();
mSpeedRates.clear();
@@ -209,7 +210,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
const int keyCount = mProximityInfo->getKeyCount();
mNearKeysVector.resize(mSampledInputSize);
mSearchKeysVector.resize(mSampledInputSize);
- mDistanceCache.resize(mSampledInputSize * keyCount);
+ mDistanceCache_G.resize(mSampledInputSize * keyCount);
for (int i = lastSavedInputSize; i < mSampledInputSize; ++i) {
mNearKeysVector[i].reset();
mSearchKeysVector[i].reset();
@@ -220,7 +221,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
const int y = mSampledInputYs[i];
const float normalizedSquaredDistance =
mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
- mDistanceCache[index] = normalizedSquaredDistance;
+ mDistanceCache_G[index] = normalizedSquaredDistance;
if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) {
mNearKeysVector[i][k] = true;
}
@@ -486,7 +487,7 @@ bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSiz
// Assuming the cache is invalid if the previous input size is larger than the new one.
return false;
}
- for (int i = 0; i < mSampledInputSize && i < MAX_WORD_LENGTH_INTERNAL; ++i) {
+ for (int i = 0; i < mSampledInputSize && i < MAX_WORD_LENGTH; ++i) {
if (xCoordinates[i] != mSampledInputXs[i]
|| yCoordinates[i] != mSampledInputYs[i]) {
return false;
@@ -685,7 +686,7 @@ float ProximityInfoState::getPointToKeyLength(
const int keyId = mProximityInfo->getKeyIndexOf(codePoint);
if (keyId != NOT_AN_INDEX) {
const int index = inputIndex * mProximityInfo->getKeyCount() + keyId;
- return min(mDistanceCache[index] * scale, mMaxPointToKeyLength);
+ return min(mDistanceCache_G[index] * scale, mMaxPointToKeyLength);
}
if (isSkippableCodePoint(codePoint)) {
return 0.0f;
@@ -694,7 +695,7 @@ float ProximityInfoState::getPointToKeyLength(
return MAX_POINT_TO_KEY_LENGTH;
}
-float ProximityInfoState::getPointToKeyLength(const int inputIndex, const int codePoint) const {
+float ProximityInfoState::getPointToKeyLength_G(const int inputIndex, const int codePoint) const {
return getPointToKeyLength(inputIndex, codePoint, 1.0f);
}
@@ -705,7 +706,7 @@ float ProximityInfoState::getPointToKeyByIdLength(
const int inputIndex, const int keyId, const float scale) const {
if (keyId != NOT_AN_INDEX) {
const int index = inputIndex * mProximityInfo->getKeyCount() + keyId;
- return min(mDistanceCache[index] * scale, mMaxPointToKeyLength);
+ return min(mDistanceCache_G[index] * scale, mMaxPointToKeyLength);
}
// If the char is not a key on the keyboard then return the max length.
return static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
@@ -1184,7 +1185,7 @@ float ProximityInfoState::getMostProbableString(int *const codePointBuf) const {
int index = 0;
float sumLogProbability = 0.0f;
// TODO: Current implementation is greedy algorithm. DP would be efficient for many cases.
- for (int i = 0; i < mSampledInputSize && index < MAX_WORD_LENGTH_INTERNAL - 1; ++i) {
+ for (int i = 0; i < mSampledInputSize && index < MAX_WORD_LENGTH - 1; ++i) {
float minLogProbability = static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
int character = NOT_AN_INDEX;
for (hash_map_compat<int, float>::const_iterator it = mCharProbabilities[i].begin();
diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h
index 10e74a0a3..d747bae2a 100644
--- a/native/jni/src/proximity_info_state.h
+++ b/native/jni/src/proximity_info_state.h
@@ -24,7 +24,6 @@
#include "char_utils.h"
#include "defines.h"
-#include "geometry_utils.h"
#include "hash_map_compat.h"
namespace latinime {
@@ -59,7 +58,7 @@ class ProximityInfoState {
mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mLocaleStr(),
mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0),
mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mTimes(),
- mInputIndice(), mLengthCache(), mBeelineSpeedPercentiles(), mDistanceCache(),
+ mInputIndice(), mLengthCache(), mBeelineSpeedPercentiles(), mDistanceCache_G(),
mSpeedRates(), mDirections(), mCharProbabilities(), mNearKeysVector(),
mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) {
memset(mInputCodes, 0, sizeof(mInputCodes));
@@ -158,7 +157,7 @@ class ProximityInfoState {
float getPointToKeyByIdLength(const int inputIndex, const int keyId, const float scale) const;
float getPointToKeyByIdLength(const int inputIndex, const int keyId) const;
float getPointToKeyLength(const int inputIndex, const int codePoint, const float scale) const;
- float getPointToKeyLength(const int inputIndex, const int codePoint) const;
+ float getPointToKeyLength_G(const int inputIndex, const int codePoint) const;
ProximityType getMatchedProximityId(const int index, const int c,
const bool checkProximityChars, int *proximityIndex = 0) const;
@@ -275,7 +274,7 @@ class ProximityInfoState {
std::vector<int> mInputIndice;
std::vector<int> mLengthCache;
std::vector<int> mBeelineSpeedPercentiles;
- std::vector<float> mDistanceCache;
+ std::vector<float> mDistanceCache_G;
std::vector<float> mSpeedRates;
std::vector<float> mDirections;
// probabilities of skipping or mapping to a key for each point.
@@ -290,10 +289,10 @@ class ProximityInfoState {
// inputs including the current input point.
std::vector<NearKeycodesSet> mSearchKeysVector;
bool mTouchPositionCorrectionEnabled;
- int mInputCodes[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH_INTERNAL];
- int mNormalizedSquaredDistances[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH_INTERNAL];
+ int mInputCodes[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH];
+ int mNormalizedSquaredDistances[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH];
int mSampledInputSize;
- int mPrimaryInputWord[MAX_WORD_LENGTH_INTERNAL];
+ int mPrimaryInputWord[MAX_WORD_LENGTH];
};
} // namespace latinime
#endif // LATINIME_PROXIMITY_INFO_STATE_H
diff --git a/native/jni/src/suggest/gesture_suggest.cpp b/native/jni/src/suggest/gesture_suggest.cpp
index 2a604b8ab..fce5621d5 100644
--- a/native/jni/src/suggest/gesture_suggest.cpp
+++ b/native/jni/src/suggest/gesture_suggest.cpp
@@ -17,7 +17,7 @@
#include "gesture_suggest.h"
namespace latinime {
- SuggestInterface *(*GestureSuggest::sGestureSuggestFactoryMethod)(int, int) = 0;
+ SuggestInterface *(*GestureSuggest::sGestureSuggestFactoryMethod)() = 0;
GestureSuggest::~GestureSuggest() {
delete mSuggestInterface;
diff --git a/native/jni/src/suggest/gesture_suggest.h b/native/jni/src/suggest/gesture_suggest.h
index e4af03fb8..82c3a69ad 100644
--- a/native/jni/src/suggest/gesture_suggest.h
+++ b/native/jni/src/suggest/gesture_suggest.h
@@ -26,37 +26,35 @@ class ProximityInfo;
class GestureSuggest : public SuggestInterface {
public:
- GestureSuggest(const int maxWordLength, const int maxWords)
- : mSuggestInterface(getGestureSuggestInstance(maxWordLength, maxWords)) {
- }
+ GestureSuggest() : mSuggestInterface(getGestureSuggestInstance()) {}
virtual ~GestureSuggest();
int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs,
- int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, int *outWords,
- int *frequencies, int *outputIndices, int *outputTypes) const {
+ int *times, int *pointerIds, int *inputCodePoints, int inputSize, int commitPoint,
+ int *outWords, int *frequencies, int *outputIndices, int *outputTypes) const {
if (!mSuggestInterface) {
return 0;
}
return mSuggestInterface->getSuggestions(pInfo, traverseSession, inputXs, inputYs, times,
- pointerIds, codes, inputSize, commitPoint, outWords, frequencies, outputIndices,
- outputTypes);
+ pointerIds, inputCodePoints, inputSize, commitPoint, outWords, frequencies,
+ outputIndices, outputTypes);
}
- static void setGestureSuggestFactoryMethod(SuggestInterface *(*factoryMethod)(int, int)) {
+ static void setGestureSuggestFactoryMethod(SuggestInterface *(*factoryMethod)()) {
sGestureSuggestFactoryMethod = factoryMethod;
}
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(GestureSuggest);
- static SuggestInterface *getGestureSuggestInstance(int maxWordLength, int maxWords) {
+ DISALLOW_COPY_AND_ASSIGN(GestureSuggest);
+ static SuggestInterface *getGestureSuggestInstance() {
if (!sGestureSuggestFactoryMethod) {
return 0;
}
- return sGestureSuggestFactoryMethod(maxWordLength, maxWords);
+ return sGestureSuggestFactoryMethod();
}
- static SuggestInterface *(*sGestureSuggestFactoryMethod)(int, int);
+ static SuggestInterface *(*sGestureSuggestFactoryMethod)();
SuggestInterface *mSuggestInterface;
};
} // namespace latinime
diff --git a/native/jni/src/suggest/suggest_interface.h b/native/jni/src/suggest/suggest_interface.h
index 0fb54266c..0bb85d7e5 100644
--- a/native/jni/src/suggest/suggest_interface.h
+++ b/native/jni/src/suggest/suggest_interface.h
@@ -26,8 +26,9 @@ class ProximityInfo;
class SuggestInterface {
public:
virtual int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs,
- int *inputYs, int *times, int *pointerIds, int *codes, int inputSize, int commitPoint,
- int *outWords, int *frequencies, int *outputIndices, int *outputTypes) const = 0;
+ int *inputYs, int *times, int *pointerIds, int *inputCodePoints, int inputSize,
+ int commitPoint, int *outWords, int *frequencies, int *outputIndices,
+ int *outputTypes) const = 0;
SuggestInterface() {}
virtual ~SuggestInterface() {}
private:
diff --git a/native/jni/src/suggest/typing_suggest.cpp b/native/jni/src/suggest/typing_suggest.cpp
index 40d4a98b0..56bd5b69a 100644
--- a/native/jni/src/suggest/typing_suggest.cpp
+++ b/native/jni/src/suggest/typing_suggest.cpp
@@ -17,7 +17,7 @@
#include "typing_suggest.h"
namespace latinime {
- SuggestInterface *(*TypingSuggest::sTypingSuggestFactoryMethod)(int, int) = 0;
+ SuggestInterface *(*TypingSuggest::sTypingSuggestFactoryMethod)() = 0;
TypingSuggest::~TypingSuggest() {
delete mSuggestInterface;
diff --git a/native/jni/src/suggest/typing_suggest.h b/native/jni/src/suggest/typing_suggest.h
index 9de4158f5..678037aa2 100644
--- a/native/jni/src/suggest/typing_suggest.h
+++ b/native/jni/src/suggest/typing_suggest.h
@@ -26,37 +26,35 @@ class ProximityInfo;
class TypingSuggest : public SuggestInterface {
public:
- TypingSuggest(const int maxWordLength, const int maxWords)
- : mSuggestInterface(getTypingSuggestInstance(maxWordLength, maxWords)) {
- }
+ TypingSuggest() : mSuggestInterface(getTypingSuggestInstance()) {}
virtual ~TypingSuggest();
int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs,
- int *times, int *pointerIds, int *codes, int inputSize, int commitPoint, int *outWords,
- int *frequencies, int *outputIndices, int *outputTypes) const {
+ int *times, int *pointerIds, int *inputCodePoints, int inputSize, int commitPoint,
+ int *outWords, int *frequencies, int *outputIndices, int *outputTypes) const {
if (!mSuggestInterface) {
return 0;
}
return mSuggestInterface->getSuggestions(pInfo, traverseSession, inputXs, inputYs, times,
- pointerIds, codes, inputSize, commitPoint, outWords, frequencies, outputIndices,
- outputTypes);
+ pointerIds, inputCodePoints, inputSize, commitPoint, outWords, frequencies,
+ outputIndices, outputTypes);
}
- static void setTypingSuggestFactoryMethod(SuggestInterface *(*factoryMethod)(int, int)) {
+ static void setTypingSuggestFactoryMethod(SuggestInterface *(*factoryMethod)()) {
sTypingSuggestFactoryMethod = factoryMethod;
}
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(TypingSuggest);
- static SuggestInterface *getTypingSuggestInstance(int maxWordLength, int maxWords) {
+ DISALLOW_COPY_AND_ASSIGN(TypingSuggest);
+ static SuggestInterface *getTypingSuggestInstance() {
if (!sTypingSuggestFactoryMethod) {
return 0;
}
- return sTypingSuggestFactoryMethod(maxWordLength, maxWords);
+ return sTypingSuggestFactoryMethod();
}
- static SuggestInterface *(*sTypingSuggestFactoryMethod)(int, int);
+ static SuggestInterface *(*sTypingSuggestFactoryMethod)();
SuggestInterface *mSuggestInterface;
};
} // namespace latinime
diff --git a/native/jni/src/suggest_utils.h b/native/jni/src/suggest_utils.h
new file mode 100644
index 000000000..42cc5dea0
--- /dev/null
+++ b/native/jni/src/suggest_utils.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_SUGGEST_UTILS_H
+#define LATINIME_SUGGEST_UTILS_H
+
+#include "defines.h"
+#include "proximity_info_state.h"
+
+namespace latinime {
+class SuggestUtils {
+ public:
+ static float getDistanceScalingFactor(const float normalizedSquaredDistance) {
+ if (normalizedSquaredDistance < 0.0f) {
+ return -1.0f;
+ }
+ // Promote or demote the score according to the distance from the sweet spot
+ static const float A = ZERO_DISTANCE_PROMOTION_RATE / 100.0f;
+ static const float B = 1.0f;
+ static const float C = 0.5f;
+ static const float MIN = 0.3f;
+ static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS;
+ static const float R2 = HALF_SCORE_SQUARED_RADIUS;
+ const float x = normalizedSquaredDistance / static_cast<float>(
+ ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
+ const float factor = max((x < R1)
+ ? (A * (R1 - x) + B * x) / R1
+ : (B * (R2 - x) + C * (x - R1)) / (R2 - R1), MIN);
+ // factor is a piecewise linear function like:
+ // A -_ .
+ // ^-_ .
+ // B \ .
+ // \_ .
+ // C ------------.
+ // .
+ // 0 R1 R2 .
+ return factor;
+ }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SuggestUtils);
+};
+} // namespace latinime
+#endif // LATINIME_SUGGEST_UTILS_H
diff --git a/native/jni/src/terminal_attributes.h b/native/jni/src/terminal_attributes.h
index 6c2e0dce1..a8cc03b8d 100644
--- a/native/jni/src/terminal_attributes.h
+++ b/native/jni/src/terminal_attributes.h
@@ -30,10 +30,6 @@ namespace latinime {
class TerminalAttributes {
public:
class ShortcutIterator {
- const uint8_t *const mDict;
- int mPos;
- bool mHasNextShortcutTarget;
-
public:
ShortcutIterator(const uint8_t *dict, const int pos, const uint8_t flags)
: mDict(dict), mPos(pos),
@@ -50,7 +46,7 @@ class TerminalAttributes {
const int shortcutFlags = BinaryFormat::getFlagsAndForwardPointer(mDict, &mPos);
mHasNextShortcutTarget = 0 != (shortcutFlags & BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT);
unsigned int i;
- for (i = 0; i < MAX_WORD_LENGTH_INTERNAL; ++i) {
+ for (i = 0; i < MAX_WORD_LENGTH; ++i) {
const int codePoint = BinaryFormat::getCodePointAndForwardPointer(mDict, &mPos);
if (NOT_A_CODE_POINT == codePoint) break;
outWord[i] = codePoint;
@@ -58,6 +54,11 @@ class TerminalAttributes {
*outFreq = BinaryFormat::getAttributeFrequencyFromFlags(shortcutFlags);
return i;
}
+
+ private:
+ const uint8_t *const mDict;
+ int mPos;
+ bool mHasNextShortcutTarget;
};
TerminalAttributes(const uint8_t *const dict, const uint8_t flags, const int pos)
diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp
index 0a144253a..0b18e78a3 100644
--- a/native/jni/src/unigram_dictionary.cpp
+++ b/native/jni/src/unigram_dictionary.cpp
@@ -40,10 +40,9 @@ const UnigramDictionary::digraph_t UnigramDictionary::FRENCH_LIGATURES_DIGRAPHS[
{ 'o', 'e', 0x0153 } }; // U+0153 : LATIN SMALL LIGATURE OE
// TODO: check the header
-UnigramDictionary::UnigramDictionary(const uint8_t *const streamStart, int maxWordLength,
- int maxWords, const unsigned int flags)
- : DICT_ROOT(streamStart), MAX_WORD_LENGTH(maxWordLength), MAX_WORDS(maxWords),
- ROOT_POS(0), MAX_DIGRAPH_SEARCH_DEPTH(DEFAULT_MAX_DIGRAPH_SEARCH_DEPTH), FLAGS(flags) {
+UnigramDictionary::UnigramDictionary(const uint8_t *const streamStart, const unsigned int flags)
+ : DICT_ROOT(streamStart), ROOT_POS(0),
+ MAX_DIGRAPH_SEARCH_DEPTH(DEFAULT_MAX_DIGRAPH_SEARCH_DEPTH), FLAGS(flags) {
if (DEBUG_DICT) {
AKLOGI("UnigramDictionary - constructor");
}
@@ -52,21 +51,17 @@ UnigramDictionary::UnigramDictionary(const uint8_t *const streamStart, int maxWo
UnigramDictionary::~UnigramDictionary() {
}
-static inline int getCodesBufferSize(const int *codes, const int codesSize) {
- return sizeof(*codes) * codesSize;
-}
-
// TODO: This needs to take a const int* and not tinker with its contents
static void addWord(int *word, int length, int frequency, WordsPriorityQueue *queue, int type) {
queue->push(frequency, word, length, type);
}
// Return the replacement code point for a digraph, or 0 if none.
-int UnigramDictionary::getDigraphReplacement(const int *codes, const int i, const int codesSize,
+int UnigramDictionary::getDigraphReplacement(const int *codes, const int i, const int inputSize,
const digraph_t *const digraphs, const unsigned int digraphsSize) const {
// There can't be a digraph if we don't have at least 2 characters to examine
- if (i + 2 > codesSize) return false;
+ if (i + 2 > inputSize) return false;
// Search for the first char of some digraph
int lastDigraphIndex = -1;
@@ -87,7 +82,7 @@ int UnigramDictionary::getDigraphReplacement(const int *codes, const int i, cons
// Mostly the same arguments as the non-recursive version, except:
// codes is the original value. It points to the start of the work buffer, and gets passed as is.
-// codesSize is the size of the user input (thus, it is the size of codesSrc).
+// inputSize is the size of the user input (thus, it is the size of codesSrc).
// codesDest is the current point in the work buffer.
// codesSrc is the current point in the user-input, original, content-unmodified buffer.
// codesRemain is the remaining size in codesSrc.
@@ -167,49 +162,49 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit
// bigramFilter is a bloom filter for fast rejection: see functions setInFilter and isInFilter
// in bigram_dictionary.cpp
int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
- const int *ycoordinates, const int *codes, const int codesSize,
+ const int *ycoordinates, const int *inputCodePoints, const int inputSize,
const std::map<int, int> *bigramMap, const uint8_t *bigramFilter,
const bool useFullEditDistance, int *outWords, int *frequencies, int *outputTypes) const {
- WordsPriorityQueuePool queuePool(MAX_WORDS, SUB_QUEUE_MAX_WORDS, MAX_WORD_LENGTH);
+ WordsPriorityQueuePool queuePool(MAX_RESULTS, SUB_QUEUE_MAX_WORDS);
queuePool.clearAll();
Correction masterCorrection;
masterCorrection.resetCorrection();
if (BinaryFormat::REQUIRES_GERMAN_UMLAUT_PROCESSING & FLAGS)
{ // Incrementally tune the word and try all possibilities
- int codesBuffer[getCodesBufferSize(codes, codesSize)];
- int xCoordinatesBuffer[codesSize];
- int yCoordinatesBuffer[codesSize];
+ int codesBuffer[sizeof(*inputCodePoints) * inputSize];
+ int xCoordinatesBuffer[inputSize];
+ int yCoordinatesBuffer[inputSize];
getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer,
- xCoordinatesBuffer, yCoordinatesBuffer, codesSize, bigramMap, bigramFilter,
- useFullEditDistance, codes, codesSize, 0, codesBuffer, &masterCorrection,
+ xCoordinatesBuffer, yCoordinatesBuffer, inputSize, bigramMap, bigramFilter,
+ useFullEditDistance, inputCodePoints, inputSize, 0, codesBuffer, &masterCorrection,
&queuePool, GERMAN_UMLAUT_DIGRAPHS, NELEMS(GERMAN_UMLAUT_DIGRAPHS));
} else if (BinaryFormat::REQUIRES_FRENCH_LIGATURES_PROCESSING & FLAGS) {
- int codesBuffer[getCodesBufferSize(codes, codesSize)];
- int xCoordinatesBuffer[codesSize];
- int yCoordinatesBuffer[codesSize];
+ int codesBuffer[sizeof(*inputCodePoints) * inputSize];
+ int xCoordinatesBuffer[inputSize];
+ int yCoordinatesBuffer[inputSize];
getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer,
- xCoordinatesBuffer, yCoordinatesBuffer, codesSize, bigramMap, bigramFilter,
- useFullEditDistance, codes, codesSize, 0, codesBuffer, &masterCorrection,
+ xCoordinatesBuffer, yCoordinatesBuffer, inputSize, bigramMap, bigramFilter,
+ useFullEditDistance, inputCodePoints, inputSize, 0, codesBuffer, &masterCorrection,
&queuePool, FRENCH_LIGATURES_DIGRAPHS, NELEMS(FRENCH_LIGATURES_DIGRAPHS));
} else { // Normal processing
- getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize,
+ getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, inputCodePoints, inputSize,
bigramMap, bigramFilter, useFullEditDistance, &masterCorrection, &queuePool);
}
PROF_START(20);
if (DEBUG_DICT) {
float ns = queuePool.getMasterQueue()->getHighestNormalizedScore(
- masterCorrection.getPrimaryInputWord(), codesSize, 0, 0, 0);
+ masterCorrection.getPrimaryInputWord(), inputSize, 0, 0, 0);
ns += 0;
AKLOGI("Max normalized score = %f", ns);
}
const int suggestedWordsCount =
queuePool.getMasterQueue()->outputSuggestions(masterCorrection.getPrimaryInputWord(),
- codesSize, frequencies, outWords, outputTypes);
+ inputSize, frequencies, outWords, outputTypes);
if (DEBUG_DICT) {
float ns = queuePool.getMasterQueue()->getHighestNormalizedScore(
- masterCorrection.getPrimaryInputWord(), codesSize, 0, 0, 0);
+ masterCorrection.getPrimaryInputWord(), inputSize, 0, 0, 0);
ns += 0;
AKLOGI("Returning %d words", suggestedWordsCount);
/// Print the returned words
@@ -227,7 +222,7 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *x
}
void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
- const int *ycoordinates, const int *codes, const int inputSize,
+ const int *ycoordinates, const int *inputCodePoints, const int inputSize,
const std::map<int, int> *bigramMap, const uint8_t *bigramFilter,
const bool useFullEditDistance, Correction *correction, WordsPriorityQueuePool *queuePool)
const {
@@ -236,8 +231,8 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo, const i
PROF_END(0);
PROF_START(1);
- getOneWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, bigramMap, bigramFilter,
- useFullEditDistance, inputSize, correction, queuePool);
+ getOneWordSuggestions(proximityInfo, xcoordinates, ycoordinates, inputCodePoints, bigramMap,
+ bigramFilter, useFullEditDistance, inputSize, correction, queuePool);
PROF_END(1);
PROF_START(2);
@@ -262,7 +257,7 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo, const i
// Multiple word suggestions
if (SUGGEST_MULTIPLE_WORDS
&& inputSize >= MIN_USER_TYPED_LENGTH_FOR_MULTIPLE_WORD_SUGGESTION) {
- getSplitMultipleWordsSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
+ getSplitMultipleWordsSuggestions(proximityInfo, xcoordinates, ycoordinates, inputCodePoints,
useFullEditDistance, inputSize, correction, queuePool,
hasAutoCorrectionCandidate);
}
@@ -398,10 +393,10 @@ void UnigramDictionary::onTerminal(const int probability,
// so that the insert order is protected inside the queue for words
// with the same score. For the moment we use -1 to make sure the shortcut will
// never be in front of the word.
- int shortcutTarget[MAX_WORD_LENGTH_INTERNAL];
+ int shortcutTarget[MAX_WORD_LENGTH];
int shortcutFrequency;
const int shortcutTargetStringLength = iterator.getNextShortcutTarget(
- MAX_WORD_LENGTH_INTERNAL, shortcutTarget, &shortcutFrequency);
+ MAX_WORD_LENGTH, shortcutTarget, &shortcutFrequency);
int shortcutScore;
int kind;
if (shortcutFrequency == BinaryFormat::WHITELIST_SHORTCUT_FREQUENCY
@@ -487,7 +482,7 @@ int UnigramDictionary::getSubStringSuggestion(
initSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
inputSize, correction);
- int word[MAX_WORD_LENGTH_INTERNAL];
+ int word[MAX_WORD_LENGTH];
int freq = getMostFrequentWordLike(
inputWordStartPos, inputWordLength, correction, word);
if (freq > 0) {
@@ -761,13 +756,13 @@ static inline void onTerminalWordLike(const int freq, int *newWord, const int le
// that is, everything that only differs by case/accents.
int UnigramDictionary::getMostFrequentWordLikeInner(const int *const inWord, const int inputSize,
int *outWord) const {
- int newWord[MAX_WORD_LENGTH_INTERNAL];
+ int newWord[MAX_WORD_LENGTH];
int depth = 0;
int maxFreq = -1;
const uint8_t *const root = DICT_ROOT;
- int stackChildCount[MAX_WORD_LENGTH_INTERNAL];
- int stackInputIndex[MAX_WORD_LENGTH_INTERNAL];
- int stackSiblingPos[MAX_WORD_LENGTH_INTERNAL];
+ int stackChildCount[MAX_WORD_LENGTH];
+ int stackInputIndex[MAX_WORD_LENGTH];
+ int stackSiblingPos[MAX_WORD_LENGTH];
int startPos = 0;
stackChildCount[0] = BinaryFormat::getGroupCountAndForwardPointer(root, &startPos);
diff --git a/native/jni/src/unigram_dictionary.h b/native/jni/src/unigram_dictionary.h
index f5850b4f4..502bf4790 100644
--- a/native/jni/src/unigram_dictionary.h
+++ b/native/jni/src/unigram_dictionary.h
@@ -39,12 +39,11 @@ class UnigramDictionary {
static const int FLAG_MULTIPLE_SUGGEST_ABORT = 0;
static const int FLAG_MULTIPLE_SUGGEST_SKIP = 1;
static const int FLAG_MULTIPLE_SUGGEST_CONTINUE = 2;
- UnigramDictionary(const uint8_t *const streamStart, int maxWordLength, int maxWords,
- const unsigned int flags);
+ UnigramDictionary(const uint8_t *const streamStart, const unsigned int flags);
int getFrequency(const int *const inWord, const int length) const;
int getBigramPosition(int pos, int *word, int offset, int length) const;
int getSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
- const int *ycoordinates, const int *codes, const int codesSize,
+ const int *ycoordinates, const int *inputCodePoints, const int inputSize,
const std::map<int, int> *bigramMap, const uint8_t *bigramFilter,
const bool useFullEditDistance, int *outWords, int *frequencies,
int *outputTypes) const;
@@ -53,11 +52,11 @@ class UnigramDictionary {
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(UnigramDictionary);
void getWordSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
- const int *ycoordinates, const int *codes, const int inputSize,
+ const int *ycoordinates, const int *inputCodePoints, const int inputSize,
const std::map<int, int> *bigramMap, const uint8_t *bigramFilter,
const bool useFullEditDistance, Correction *correction,
WordsPriorityQueuePool *queuePool) const;
- int getDigraphReplacement(const int *codes, const int i, const int codesSize,
+ int getDigraphReplacement(const int *codes, const int i, const int inputSize,
const digraph_t *const digraphs, const unsigned int digraphsSize) const;
void getWordWithDigraphSuggestionsRec(ProximityInfo *proximityInfo, const int *xcoordinates,
const int *ycoordinates, const int *codesBuffer, int *xCoordinatesBuffer,
@@ -67,7 +66,7 @@ class UnigramDictionary {
WordsPriorityQueuePool *queuePool, const digraph_t *const digraphs,
const unsigned int digraphsSize) const;
void initSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
- const int *ycoordinates, const int *codes, const int codesSize,
+ const int *ycoordinates, const int *codes, const int inputSize,
Correction *correction) const;
void getOneWordSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
const int *ycoordinates, const int *codes, const std::map<int, int> *bigramMap,
@@ -109,8 +108,6 @@ class UnigramDictionary {
int *outputWord) const;
const uint8_t *const DICT_ROOT;
- const int MAX_WORD_LENGTH;
- const int MAX_WORDS;
const int ROOT_POS;
const int MAX_DIGRAPH_SEARCH_DEPTH;
const int FLAGS;
diff --git a/native/jni/src/words_priority_queue.h b/native/jni/src/words_priority_queue.h
index 84b4b484f..7aab1e083 100644
--- a/native/jni/src/words_priority_queue.h
+++ b/native/jni/src/words_priority_queue.h
@@ -27,10 +27,9 @@ namespace latinime {
class WordsPriorityQueue {
public:
- class SuggestedWord {
- public:
+ struct SuggestedWord {
int mScore;
- int mWord[MAX_WORD_LENGTH_INTERNAL];
+ int mWord[MAX_WORD_LENGTH];
int mWordLength;
bool mUsed;
int mType;
@@ -44,11 +43,10 @@ class WordsPriorityQueue {
}
};
- WordsPriorityQueue(int maxWords, int maxWordLength)
- : mSuggestions(), MAX_WORDS(static_cast<unsigned int>(maxWords)),
- MAX_WORD_LENGTH(static_cast<unsigned int>(maxWordLength)),
- mSuggestedWords(new SuggestedWord[maxWordLength]), mHighestSuggestedWord(0) {
- for (int i = 0; i < maxWordLength; ++i) {
+ WordsPriorityQueue(int maxWords)
+ : mSuggestions(), MAX_WORDS(maxWords),
+ mSuggestedWords(new SuggestedWord[MAX_WORD_LENGTH]), mHighestSuggestedWord(0) {
+ for (int i = 0; i < MAX_WORD_LENGTH; ++i) {
mSuggestedWords[i].mUsed = false;
}
}
@@ -171,7 +169,6 @@ class WordsPriorityQueue {
wordComparator> Suggestions;
Suggestions mSuggestions;
const int MAX_WORDS;
- const int MAX_WORD_LENGTH;
SuggestedWord *mSuggestedWords;
SuggestedWord *mHighestSuggestedWord;
};
diff --git a/native/jni/src/words_priority_queue_pool.h b/native/jni/src/words_priority_queue_pool.h
index f7c08fb52..cfe7ede63 100644
--- a/native/jni/src/words_priority_queue_pool.h
+++ b/native/jni/src/words_priority_queue_pool.h
@@ -24,15 +24,14 @@ namespace latinime {
class WordsPriorityQueuePool {
public:
- WordsPriorityQueuePool(int mainQueueMaxWords, int subQueueMaxWords, int maxWordLength)
+ WordsPriorityQueuePool(int mainQueueMaxWords, int subQueueMaxWords)
// Note: using placement new() requires the caller to call the destructor explicitly.
- : mMasterQueue(new(mMasterQueueBuf) WordsPriorityQueue(
- mainQueueMaxWords, maxWordLength)) {
+ : mMasterQueue(new(mMasterQueueBuf) WordsPriorityQueue(mainQueueMaxWords)) {
for (int i = 0, subQueueBufOffset = 0;
i < MULTIPLE_WORDS_SUGGESTION_MAX_WORDS * SUB_QUEUE_MAX_COUNT;
++i, subQueueBufOffset += static_cast<int>(sizeof(WordsPriorityQueue))) {
mSubQueues[i] = new(mSubQueueBuf + subQueueBufOffset)
- WordsPriorityQueue(subQueueMaxWords, maxWordLength);
+ WordsPriorityQueue(subQueueMaxWords);
}
}
diff --git a/tools/maketext/res/values-ar/donottranslate-more-keys.xml b/tools/maketext/res/values-ar/donottranslate-more-keys.xml
index c404bed94..f10139e09 100644
--- a/tools/maketext/res/values-ar/donottranslate-more-keys.xml
+++ b/tools/maketext/res/values-ar/donottranslate-more-keys.xml
@@ -139,6 +139,7 @@
U+064E: "َ" ARABIC FATHA
U+0640: "ـ" ARABIC TATWEEL -->
<!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. -->
- <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!7,&#x0655;,&#x0654;,&#x0652;,&#x064D;,&#x064C;,&#x064B;,&#x0651;,&#x0656;,&#x0670;,&#x0653;,&#x0650;,&#x064F;,&#x064E;,&#x0640;&#x0640;&#x0640;|&#x0640;"</string>
+ <!-- Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly. -->
+ <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!7,&#x20;&#x0655;|&#x0655;,&#x20;&#x0654;|&#x0654;,&#x20;&#x0652;|&#x0652;,&#x20;&#x064D;|&#x064D;,&#x20;&#x064C;|&#x064C;,&#x20;&#x064B;|&#x064B;,&#x20;&#x0651;|&#x0651;,&#x20;&#x0656;|&#x0656;,&#x20;&#x0670;|&#x0670;,&#x20;&#x0653;|&#x0653;,&#x20;&#x0650;|&#x0650;,&#x20;&#x064F;|&#x064F;,&#x20;&#x064E;|&#x064E;,&#x0640;&#x0640;&#x0640;|&#x0640;"</string>
<string name="keyhintlabel_for_arabic_diacritics">&#x0651;</string>
</resources>
diff --git a/tools/maketext/res/values-fa/donottranslate-more-keys.xml b/tools/maketext/res/values-fa/donottranslate-more-keys.xml
index 47f21cc15..6acdd41a8 100644
--- a/tools/maketext/res/values-fa/donottranslate-more-keys.xml
+++ b/tools/maketext/res/values-fa/donottranslate-more-keys.xml
@@ -148,6 +148,7 @@
U+064E: "َ" ARABIC FATHA
U+0640: "ـ" ARABIC TATWEEL -->
<!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. -->
- <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!7,&#x0655;,&#x0652;,&#x0651;,&#x064C;,&#x064D;,&#x064B;,&#x0654;,&#x0656;,&#x0670;,&#x0653;,&#x064F;,&#x0650;,&#x064E;,&#x0640;&#x0640;&#x0640;|&#x0640;"</string>
+ <!-- Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly. -->
+ <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!7,&#x20;&#x0655;|&#x0655;,&#x20;&#x0652;|&#x0652;,&#x20;&#x0651;|&#x0651;,&#x20;&#x064C;|&#x064C;,&#x20;&#x064D;|&#x064D;,&#x20;&#x064B;|&#x064B;,&#x20;&#x0654;|&#x0654;,&#x20;&#x0656;|&#x0656;,&#x20;&#x0670;|&#x0670;,&#x20;&#x0653;|&#x0653;,&#x20;&#x064F;|&#x064F;,&#x20;&#x0650;|&#x0650;,&#x20;&#x064E;|&#x064E;,&#x0640;&#x0640;&#x0640;|&#x0640;"</string>
<string name="keyhintlabel_for_arabic_diacritics">&#x064B;</string>
</resources>
diff --git a/tools/maketext/src/com/android/inputmethod/latin/maketext/StringResourceMap.java b/tools/maketext/src/com/android/inputmethod/latin/maketext/StringResourceMap.java
index 6ceea5a37..ff133425c 100644
--- a/tools/maketext/src/com/android/inputmethod/latin/maketext/StringResourceMap.java
+++ b/tools/maketext/src/com/android/inputmethod/latin/maketext/StringResourceMap.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin.maketext;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
import org.xml.sax.ext.DefaultHandler2;
import java.io.IOException;
@@ -48,6 +49,9 @@ public class StringResourceMap {
parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
parser.parse(is, handler);
} catch (ParserConfigurationException e) {
+ } catch (SAXParseException e) {
+ throw new RuntimeException(e.getMessage() + " at line " + e.getLineNumber()
+ + ", column " + e.getColumnNumber());
} catch (SAXException e) {
throw new RuntimeException(e.getMessage());
} catch (IOException e) {