aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/res/values-fr-rCA/config-spacing-and-punctuations.xml2
-rw-r--r--java/res/values-fr/config-spacing-and-punctuations.xml2
-rw-r--r--java/res/values-hy-rAM/config-spacing-and-punctuations.xml2
-rw-r--r--java/res/values/config-spacing-and-punctuations.xml2
-rw-r--r--java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java16
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java17
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java1
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryWriter.java9
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java14
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java38
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java76
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java17
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java4
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java7
-rw-r--r--java/src/com/android/inputmethod/latin/settings/Settings.java4
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java42
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java14
-rw-r--r--java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java18
-rw-r--r--java/src/com/android/inputmethod/latin/utils/StringUtils.java25
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java4
20 files changed, 169 insertions, 145 deletions
diff --git a/java/res/values-fr-rCA/config-spacing-and-punctuations.xml b/java/res/values-fr-rCA/config-spacing-and-punctuations.xml
index 06254800b..c3a1a0a01 100644
--- a/java/res/values-fr-rCA/config-spacing-and-punctuations.xml
+++ b/java/res/values-fr-rCA/config-spacing-and-punctuations.xml
@@ -25,7 +25,7 @@
<string name="symbols_followed_by_space" translatable="false">.,;:!?)]}&amp;</string>
<!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
+ <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;&#x000A;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
<!-- Word connectors -->
<string name="symbols_word_connectors" translatable="false">\'-</string>
</resources>
diff --git a/java/res/values-fr/config-spacing-and-punctuations.xml b/java/res/values-fr/config-spacing-and-punctuations.xml
index 33e0236b0..8b53fb3e8 100644
--- a/java/res/values-fr/config-spacing-and-punctuations.xml
+++ b/java/res/values-fr/config-spacing-and-punctuations.xml
@@ -24,7 +24,7 @@
<string name="symbols_followed_by_space" translatable="false">.,;:!?)]}&amp;</string>
<!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
+ <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;&#x000A;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
<!-- Word connectors -->
<string name="symbols_word_connectors" translatable="false">\'-</string>
</resources>
diff --git a/java/res/values-hy-rAM/config-spacing-and-punctuations.xml b/java/res/values-hy-rAM/config-spacing-and-punctuations.xml
index f26a30def..8bc1b85a1 100644
--- a/java/res/values-hy-rAM/config-spacing-and-punctuations.xml
+++ b/java/res/values-hy-rAM/config-spacing-and-punctuations.xml
@@ -25,7 +25,7 @@
<string name="symbols_followed_by_space" translatable="false">.,;:!?)]}&amp;&#x0589;&#x055D;</string>
<!-- Symbols that separate words. Adding armenian period and comma. -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"&#x0589;&#x055D;</string>
+ <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;&#x000A;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"&#x0589;&#x055D;</string>
<!-- The sentence separator code point, for capitalization -->
<!-- U+0589: "։" ARMENIAN FULL STOP ; 589h = 1417d -->
<integer name="sentence_separator" translatable="false">1417</integer>
diff --git a/java/res/values/config-spacing-and-punctuations.xml b/java/res/values/config-spacing-and-punctuations.xml
index f10f810dc..2f52edd4a 100644
--- a/java/res/values/config-spacing-and-punctuations.xml
+++ b/java/res/values/config-spacing-and-punctuations.xml
@@ -28,7 +28,7 @@
<string name="symbols_followed_by_space" translatable="false">.,;:!?)]}&amp;</string>
<!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
+ <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;&#x000A;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
<!-- Word connectors -->
<string name="symbols_word_connectors" translatable="false">\'-</string>
<!-- The sentence separator code point, for capitalization -->
diff --git a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
index 1aee22baf..1c6a14efe 100644
--- a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
@@ -16,12 +16,12 @@
package com.android.inputmethod.latin;
-import android.content.Context;
import android.util.Log;
import com.android.inputmethod.latin.makedict.DictEncoder;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
-import com.android.inputmethod.latin.makedict.Ver2DictEncoder;
+import com.android.inputmethod.latin.makedict.Ver4DictEncoder;
+import com.android.inputmethod.latin.utils.FileUtils;
import java.io.File;
import java.io.IOException;
@@ -31,10 +31,7 @@ abstract public class AbstractDictionaryWriter {
/** Used for Log actions from this class */
private static final String TAG = AbstractDictionaryWriter.class.getSimpleName();
- private final Context mContext;
-
- public AbstractDictionaryWriter(final Context context) {
- mContext = context;
+ public AbstractDictionaryWriter() {
}
abstract public void clear();
@@ -61,12 +58,11 @@ abstract public class AbstractDictionaryWriter {
final Map<String, String> attributeMap) throws IOException, UnsupportedFormatException;
public void write(final File file, final Map<String, String> attributeMap) {
- final String tempFilePath = file.getAbsolutePath() + ".temp";
- final File tempFile = new File(tempFilePath);
try {
- final DictEncoder dictEncoder = new Ver2DictEncoder(tempFile);
+ FileUtils.deleteRecursively(file);
+ file.mkdir();
+ final DictEncoder dictEncoder = new Ver4DictEncoder(file);
writeDictionary(dictEncoder, attributeMap);
- tempFile.renameTo(file);
} catch (IOException e) {
Log.e(TAG, "IO exception while writing file", e);
} catch (UnsupportedFormatException e) {
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 2c7998688..e66cfca49 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -165,6 +165,7 @@ public final class BinaryDictionary extends Dictionary {
LanguageModelParam[] languageModelParams, int startIndex);
private static native int calculateProbabilityNative(long dict, int unigramProbability,
int bigramProbability);
+ private static native int setCurrentTimeForTestNative(int currentTime);
private static native String getPropertyNative(long dict, String query);
@UsedForTesting
@@ -420,8 +421,22 @@ public final class BinaryDictionary extends Dictionary {
return calculateProbabilityNative(mNativeDict, unigramProbability, bigramProbability);
}
+ /**
+ * Control the current time to be used in the native code. If currentTime >= 0, this method sets
+ * the current time and gets into test mode.
+ * In test mode, set timestamp is used as the current time in the native code.
+ * If currentTime < 0, quit the test mode and returns to using time() to get the current time.
+ *
+ * @param currentTime seconds since the unix epoch
+ * @return current time got in the native code.
+ */
+ @UsedForTesting
+ public static int setCurrentTimeForTest(final int currentTime) {
+ return setCurrentTimeForTestNative(currentTime);
+ }
+
@UsedForTesting
- public String getPropertyForTests(String query) {
+ public String getPropertyForTest(final String query) {
if (!isValidDictionary()) return "";
return getPropertyNative(mNativeDict, query);
}
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 00b54f593..77e99bfba 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -183,6 +183,7 @@ public final class Constants {
public static final int CODE_TAB = '\t';
public static final int CODE_SPACE = ' ';
public static final int CODE_PERIOD = '.';
+ public static final int CODE_COMMA = ',';
public static final int CODE_ARMENIAN_PERIOD = 0x0589;
public static final int CODE_DASH = '-';
public static final int CODE_SINGLE_QUOTE = '\'';
diff --git a/java/src/com/android/inputmethod/latin/DictionaryWriter.java b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
index 89ef96d7f..84898680e 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
@@ -16,8 +16,6 @@
package com.android.inputmethod.latin;
-import android.content.Context;
-
import com.android.inputmethod.latin.makedict.DictEncoder;
import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.FusionDictionary;
@@ -35,14 +33,13 @@ import java.util.Map;
* An in memory dictionary for memorizing entries and writing a binary dictionary.
*/
public class DictionaryWriter extends AbstractDictionaryWriter {
- private static final int BINARY_DICT_VERSION = 2;
+ private static final int BINARY_DICT_VERSION = FormatSpec.VERSION4;
private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
- new FormatSpec.FormatOptions(BINARY_DICT_VERSION, false /* supportsDynamicUpdate */);
+ new FormatSpec.FormatOptions(BINARY_DICT_VERSION, false /* hasTimestamp */);
private FusionDictionary mFusionDictionary;
- public DictionaryWriter(final Context context) {
- super(context);
+ public DictionaryWriter() {
clear();
}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index ecef20efc..8e1675b2a 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -136,12 +136,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
protected abstract boolean hasContentChanged();
- protected boolean matchesExpectedBinaryDictFormatVersionForThisType(final int formatVersion) {
- // This class is using format 2 because it's used by the User and Contacts dictionary
- // only, which right now use format 2 (dicts using format 4 use Decaying*, which overrides
- // this method).
- // TODO: Migrate these dicts to ver4 format, and remove this function.
- return formatVersion == FormatSpec.VERSION2;
+ private boolean matchesExpectedBinaryDictFormatVersionForThisType(final int formatVersion) {
+ return formatVersion == FormatSpec.VERSION4;
}
public boolean isValidDictionary() {
@@ -194,12 +190,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
}
- private static AbstractDictionaryWriter getDictionaryWriter(final Context context,
+ private static AbstractDictionaryWriter getDictionaryWriter(
final boolean isDynamicPersonalizationDictionary) {
if (isDynamicPersonalizationDictionary) {
return null;
} else {
- return new DictionaryWriter(context);
+ return new DictionaryWriter();
}
}
@@ -233,7 +229,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
mBinaryDictionary = null;
mDictNameDictionaryUpdateController = getDictionaryUpdateController(dictName);
// Currently, only dynamic personalization dictionary is updatable.
- mDictionaryWriter = getDictionaryWriter(context, isUpdatable);
+ mDictionaryWriter = getDictionaryWriter(isUpdatable);
}
protected static String getDictNameWithLocale(final String name, final Locale locale) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 3fca4fd19..d3e6a1bc2 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1407,7 +1407,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO[IL]: Move this to InputLogic
public SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord,
- final SuggestedWords suggestedWords) {
+ final SuggestedWords suggestedWords, final SuggestedWords previousSuggestedWords) {
// TODO: consolidate this into getSuggestedWords
// We update the suggestion strip only when we have some suggestions to show, i.e. when
// the suggestion count is > 1; else, we leave the old suggestions, with the typed word
@@ -1420,28 +1420,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|| mSuggestionStripView.isShowingAddToDictionaryHint()) {
return suggestedWords;
} else {
- return getOlderSuggestions(typedWord);
- }
- }
-
- private SuggestedWords getOlderSuggestions(final String typedWord) {
- SuggestedWords previousSuggestedWords = mInputLogic.mSuggestedWords;
- if (previousSuggestedWords
- == mSettings.getCurrent().mSpacingAndPunctuations.mSuggestPuncList) {
- previousSuggestedWords = SuggestedWords.EMPTY;
- }
- if (typedWord == null) {
- return previousSuggestedWords;
+ final SuggestedWords punctuationList =
+ mSettings.getCurrent().mSpacingAndPunctuations.mSuggestPuncList;
+ final SuggestedWords oldSuggestedWords = previousSuggestedWords == punctuationList
+ ? SuggestedWords.EMPTY : previousSuggestedWords;
+ if (TextUtils.isEmpty(typedWord)) {
+ return oldSuggestedWords;
+ }
+ final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions =
+ SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords);
+ return new SuggestedWords(typedWordAndPreviousSuggestions,
+ false /* typedWordValid */,
+ false /* hasAutoCorrectionCandidate */,
+ false /* isPunctuationSuggestions */,
+ true /* isObsoleteSuggestions */,
+ false /* isPrediction */);
}
- final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions =
- SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord,
- previousSuggestedWords);
- return new SuggestedWords(typedWordAndPreviousSuggestions,
- false /* typedWordValid */,
- false /* hasAutoCorrectionCandidate */,
- false /* isPunctuationSuggestions */,
- true /* isObsoleteSuggestions */,
- false /* isPrediction */);
}
private void showSuggestionStripWithTypedWord(final SuggestedWords suggestedWords,
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 79d66744b..325a0d981 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -27,7 +27,6 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import com.android.inputmethod.latin.define.ProductionFlag;
-import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;
@@ -36,6 +35,7 @@ import com.android.inputmethod.latin.utils.StringUtils;
import com.android.inputmethod.latin.utils.TextRange;
import com.android.inputmethod.research.ResearchLogger;
+import java.util.Arrays;
import java.util.regex.Pattern;
/**
@@ -98,7 +98,7 @@ public final class RichInputConnection {
final ExtractedText et = mIC.getExtractedText(r, 0);
final CharSequence beforeCursor = getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE,
0);
- final StringBuilder internal = new StringBuilder().append(mCommittedTextBeforeComposingText)
+ final StringBuilder internal = new StringBuilder(mCommittedTextBeforeComposingText)
.append(mComposingText);
if (null == et || null == beforeCursor) return;
final int actualLength = Math.min(beforeCursor.length(), internal.length());
@@ -253,8 +253,7 @@ public final class RichInputConnection {
}
public CharSequence getSelectedText(final int flags) {
- if (null == mIC) return null;
- return mIC.getSelectedText(flags);
+ return (null == mIC) ? null : mIC.getSelectedText(flags);
}
public boolean canDeleteCharacters() {
@@ -272,12 +271,12 @@ public final class RichInputConnection {
* American English, it's just the most common set of rules for English).
*
* @param inputType a mask of the caps modes to test for.
- * @param settingsValues the values of the settings to use for locale and separators.
+ * @param spacingAndPunctuations the values of the settings to use for locale and separators.
* @param hasSpaceBefore if we should consider there should be a space after the string.
* @return the caps modes that should be on as a set of bits
*/
- public int getCursorCapsMode(final int inputType, final SettingsValues settingsValues,
- final boolean hasSpaceBefore) {
+ public int getCursorCapsMode(final int inputType,
+ final SpacingAndPunctuations spacingAndPunctuations, final boolean hasSpaceBefore) {
mIC = mParent.getCurrentInputConnection();
if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF;
if (!TextUtils.isEmpty(mComposingText)) {
@@ -304,13 +303,13 @@ public final class RichInputConnection {
// This never calls InputConnection#getCapsMode - in fact, it's a static method that
// never blocks or initiates IPC.
return CapsModeUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType,
- settingsValues.mSpacingAndPunctuations, hasSpaceBefore);
+ spacingAndPunctuations, hasSpaceBefore);
}
public int getCodePointBeforeCursor() {
- if (mCommittedTextBeforeComposingText.length() < 1) return Constants.NOT_A_CODE;
- return Character.codePointBefore(mCommittedTextBeforeComposingText,
- mCommittedTextBeforeComposingText.length());
+ final int length = mCommittedTextBeforeComposingText.length();
+ if (length < 1) return Constants.NOT_A_CODE;
+ return Character.codePointBefore(mCommittedTextBeforeComposingText, length);
}
public CharSequence getTextBeforeCursor(final int n, final int flags) {
@@ -338,16 +337,12 @@ public final class RichInputConnection {
return s;
}
mIC = mParent.getCurrentInputConnection();
- if (null != mIC) {
- return mIC.getTextBeforeCursor(n, flags);
- }
- return null;
+ return (null == mIC) ? null : mIC.getTextBeforeCursor(n, flags);
}
public CharSequence getTextAfterCursor(final int n, final int flags) {
mIC = mParent.getCurrentInputConnection();
- if (null != mIC) return mIC.getTextAfterCursor(n, flags);
- return null;
+ return (null == mIC) ? null : mIC.getTextAfterCursor(n, flags);
}
public void deleteSurroundingText(final int beforeLength, final int afterLength) {
@@ -563,8 +558,8 @@ public final class RichInputConnection {
return getNthPreviousWord(prev, spacingAndPunctuations, n);
}
- private static boolean isSeparator(int code, String sep) {
- return sep.indexOf(code) != -1;
+ private static boolean isSeparator(final int code, final int[] sortedSeparators) {
+ return Arrays.binarySearch(sortedSeparators, code) >= 0;
}
// Get the nth word before cursor. n = 1 retrieves the word immediately before the cursor,
@@ -603,29 +598,29 @@ public final class RichInputConnection {
}
/**
- * @param separators characters which may separate words
+ * @param sortedSeparators a sorted array of code points which may separate words
* @return the word that surrounds the cursor, including up to one trailing
* separator. For example, if the field contains "he|llo world", where |
* represents the cursor, then "hello " will be returned.
*/
- public CharSequence getWordAtCursor(String separators) {
+ public CharSequence getWordAtCursor(final int[] sortedSeparators) {
// getWordRangeAtCursor returns null if the connection is null
- TextRange r = getWordRangeAtCursor(separators, 0);
+ final TextRange r = getWordRangeAtCursor(sortedSeparators, 0);
return (r == null) ? null : r.mWord;
}
/**
* Returns the text surrounding the cursor.
*
- * @param sep a string of characters that split words.
+ * @param sortedSeparators a sorted array of code points that split words.
* @param additionalPrecedingWordsCount the number of words before the current word that should
* be included in the returned range
* @return a range containing the text surrounding the cursor
*/
- public TextRange getWordRangeAtCursor(final String sep,
+ public TextRange getWordRangeAtCursor(final int[] sortedSeparators,
final int additionalPrecedingWordsCount) {
mIC = mParent.getCurrentInputConnection();
- if (mIC == null || sep == null) {
+ if (mIC == null) {
return null;
}
final CharSequence before = mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE,
@@ -644,7 +639,7 @@ public final class RichInputConnection {
while (true) { // see comments below for why this is guaranteed to halt
while (startIndexInBefore > 0) {
final int codePoint = Character.codePointBefore(before, startIndexInBefore);
- if (isStoppingAtWhitespace == isSeparator(codePoint, sep)) {
+ if (isStoppingAtWhitespace == isSeparator(codePoint, sortedSeparators)) {
break; // inner loop
}
--startIndexInBefore;
@@ -665,7 +660,7 @@ public final class RichInputConnection {
int endIndexInAfter = -1;
while (++endIndexInAfter < after.length()) {
final int codePoint = Character.codePointAt(after, endIndexInAfter);
- if (isSeparator(codePoint, sep)) {
+ if (isSeparator(codePoint, sortedSeparators)) {
break;
}
if (Character.isSupplementaryCodePoint(codePoint)) {
@@ -681,23 +676,28 @@ public final class RichInputConnection {
startIndexInBefore, before.length() + endIndexInAfter, before.length());
}
- public boolean isCursorTouchingWord(final SettingsValues settingsValues) {
+ public boolean isCursorTouchingWord(final SpacingAndPunctuations spacingAndPunctuations) {
final int codePointBeforeCursor = getCodePointBeforeCursor();
- if (Constants.NOT_A_CODE != codePointBeforeCursor
- && !settingsValues.isWordSeparator(codePointBeforeCursor)
- && !settingsValues.isWordConnector(codePointBeforeCursor)) {
- return true;
+ if (Constants.NOT_A_CODE == codePointBeforeCursor
+ || spacingAndPunctuations.isWordSeparator(codePointBeforeCursor)
+ || spacingAndPunctuations.isWordConnector(codePointBeforeCursor)) {
+ return isCursorFollowedByWordCharacter(spacingAndPunctuations);
}
- return isCursorFollowedByWordCharacter(settingsValues);
+ return true;
}
- public boolean isCursorFollowedByWordCharacter(final SettingsValues settingsValues) {
+ public boolean isCursorFollowedByWordCharacter(
+ final SpacingAndPunctuations spacingAndPunctuations) {
final CharSequence after = getTextAfterCursor(1, 0);
- if (!TextUtils.isEmpty(after) && !settingsValues.isWordSeparator(after.charAt(0))
- && !settingsValues.isWordConnector(after.charAt(0))) {
- return true;
+ if (TextUtils.isEmpty(after)) {
+ return false;
+ }
+ final int codePointAfterCursor = Character.codePointAt(after, 0);
+ if (spacingAndPunctuations.isWordSeparator(codePointAfterCursor)
+ || spacingAndPunctuations.isWordConnector(codePointAfterCursor)) {
+ return false;
}
- return false;
+ return true;
}
public void removeTrailingSpace() {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 0c33e6b72..c040ee87d 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -534,7 +534,7 @@ public final class InputLogic {
&& settingsValues.isSuggestionsRequested() &&
// In languages with spaces, we only start composing a word when we are not already
// touching a word. In languages without spaces, the above conditions are sufficient.
- (!mConnection.isCursorTouchingWord(settingsValues)
+ (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)
|| !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces)) {
// Reset entirely the composing state anyway, then start composing a new word unless
// the character is a single quote or a dash. The idea here is, single quote and dash
@@ -816,7 +816,8 @@ public final class InputLogic {
}
if (settingsValues.isSuggestionStripVisible()
&& settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
- && !mConnection.isCursorFollowedByWordCharacter(settingsValues)) {
+ && !mConnection.isCursorFollowedByWordCharacter(
+ settingsValues.mSpacingAndPunctuations)) {
restartSuggestionsOnWordTouchedByCursor(settingsValues,
true /* includeResumedWordInSuggestions */, keyboardSwitcher);
}
@@ -969,7 +970,8 @@ public final class InputLogic {
if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection
mRecapitalizeStatus.initialize(mConnection.getExpectedSelectionStart(),
mConnection.getExpectedSelectionEnd(), selectedText.toString(),
- settingsValues.mLocale, settingsValues.mSpacingAndPunctuations.mWordSeparators);
+ settingsValues.mLocale,
+ settingsValues.mSpacingAndPunctuations.mSortedWordSeparators);
// We trim leading and trailing whitespace.
mRecapitalizeStatus.trim();
}
@@ -1030,7 +1032,8 @@ public final class InputLogic {
public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
final SuggestedWords suggestedWordsWithMaybeOlderSuggestions =
mLatinIME.maybeRetrieveOlderSuggestions(
- mWordComposer.getTypedWord(), suggestedWords);
+ mWordComposer.getTypedWord(), suggestedWords,
+ mSuggestedWords);
holder.set(suggestedWordsWithMaybeOlderSuggestions);
}
}
@@ -1069,9 +1072,9 @@ public final class InputLogic {
// If we don't know the cursor location, return.
if (mConnection.getExpectedSelectionStart() < 0) return;
final int expectedCursorPosition = mConnection.getExpectedSelectionStart();
- if (!mConnection.isCursorTouchingWord(settingsValues)) return;
+ if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) return;
final TextRange range = mConnection.getWordRangeAtCursor(
- settingsValues.mSpacingAndPunctuations.mWordSeparators,
+ settingsValues.mSpacingAndPunctuations.mSortedWordSeparators,
0 /* additionalPrecedingWordsCount */);
if (null == range) return; // Happens if we don't have an input connection at all
if (range.length() <= 0) return; // Race condition. No text to resume on, so bail out.
@@ -1290,7 +1293,7 @@ public final class InputLogic {
final int inputType = ei.inputType;
// Warning: this depends on mSpaceState, which may not be the most current value. If
// mSpaceState gets updated later, whoever called this may need to be told about it.
- return mConnection.getCursorCapsMode(inputType, settingsValues,
+ return mConnection.getCursorCapsMode(inputType, settingsValues.mSpacingAndPunctuations,
SpaceState.PHANTOM == mSpaceState);
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java
index e5430423d..a3a6c2c34 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin.makedict;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
@@ -33,6 +34,7 @@ import java.util.Iterator;
/**
* An implementation of DictEncoder for version 2 binary dictionary.
*/
+@UsedForTesting
public class Ver2DictEncoder implements DictEncoder {
private final File mDictFile;
@@ -40,6 +42,7 @@ public class Ver2DictEncoder implements DictEncoder {
private byte[] mBuffer;
private int mPosition;
+ @UsedForTesting
public Ver2DictEncoder(final File dictFile) {
mDictFile = dictFile;
mOutStream = null;
@@ -49,6 +52,7 @@ public class Ver2DictEncoder implements DictEncoder {
// This constructor is used only by BinaryDictOffdeviceUtilsTests.
// If you want to use this in the production code, you should consider keeping consistency of
// the interface of Ver3DictDecoder by using factory.
+ @UsedForTesting
public Ver2DictEncoder(final OutputStream outStream) {
mDictFile = null;
mOutStream = outStream;
diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
index cc57d13dc..4a610e6f9 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
@@ -116,13 +116,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
return false;
}
- @Override
- protected boolean matchesExpectedBinaryDictFormatVersionForThisType(final int formatVersion) {
- // This class is using format 4 because it's used by all version 4 dictionaries.
- // TODO: remove this when all dynamically generated dicts use version 4.
- return formatVersion == REQUIRED_BINARY_DICTIONARY_VERSION;
- }
-
public void addMultipleDictionaryEntriesToDictionary(
final ArrayList<LanguageModelParam> languageModelParams,
final ExpandableBinaryDictionary.AddMultipleDictionaryEntriesCallback callback) {
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 7db10714a..9bf269b6e 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -181,10 +181,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
return mSettingsValues.mIsInternal;
}
- public String getWordSeparators() {
- return mSettingsValues.mSpacingAndPunctuations.mWordSeparators;
- }
-
public boolean isWordSeparator(final int code) {
return mSettingsValues.isWordSeparator(code);
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
index dbe30e260..8ba32ff76 100644
--- a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
+++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
@@ -32,38 +32,41 @@ import java.util.Arrays;
import java.util.Locale;
public final class SpacingAndPunctuations {
- private final int[] mSymbolsPrecededBySpace;
- private final int[] mSymbolsFollowedBySpace;
- private final int[] mWordConnectors;
+ private final int[] mSortedSymbolsPrecededBySpace;
+ private final int[] mSortedSymbolsFollowedBySpace;
+ private final int[] mSortedWordConnectors;
+ public final int[] mSortedWordSeparators;
public final SuggestedWords mSuggestPuncList;
- public final String mWordSeparators;
private final int mSentenceSeparator;
public final String mSentenceSeparatorAndSpace;
public final boolean mCurrentLanguageHasSpaces;
public final boolean mUsesAmericanTypography;
+ public final boolean mUsesGermanRules;
public SpacingAndPunctuations(final Resources res) {
- 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);
+ // To be able to binary search the code point. See {@link #isUsuallyPrecededBySpace(int)}.
+ mSortedSymbolsPrecededBySpace = StringUtils.toSortedCodePointArray(
+ res.getString(R.string.symbols_preceded_by_space));
+ // To be able to binary search the code point. See {@link #isUsuallyFollowedBySpace(int)}.
+ mSortedSymbolsFollowedBySpace = StringUtils.toSortedCodePointArray(
+ res.getString(R.string.symbols_followed_by_space));
+ // To be able to binary search the code point. See {@link #isWordConnector(int)}.
+ mSortedWordConnectors = StringUtils.toSortedCodePointArray(
+ res.getString(R.string.symbols_word_connectors));
+ mSortedWordSeparators = StringUtils.toSortedCodePointArray(
+ res.getString(R.string.symbols_word_separators));
final String[] suggestPuncsSpec = KeySpecParser.splitKeySpecs(res.getString(
R.string.suggested_punctuations));
mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
- mWordSeparators = res.getString(R.string.symbols_word_separators);
mSentenceSeparator = res.getInteger(R.integer.sentence_separator);
mSentenceSeparatorAndSpace = new String(new int[] {
mSentenceSeparator, Constants.CODE_SPACE }, 0, 2);
mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces);
final Locale locale = res.getConfiguration().locale;
// Heuristic: we use American Typography rules because it's the most common rules for all
- // English variants.
+ // English variants. German rules (not "German typography") also have small gotchas.
mUsesAmericanTypography = Locale.ENGLISH.getLanguage().equals(locale.getLanguage());
+ mUsesGermanRules = Locale.GERMAN.getLanguage().equals(locale.getLanguage());
}
// Helper functions to create member values.
@@ -72,6 +75,7 @@ public final class SpacingAndPunctuations {
if (puncs != null) {
for (final String puncSpec : puncs) {
// TODO: Stop using KeySpceParser.getLabel().
+ // TODO: Punctuation suggestions should honor RTL languages.
puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED,
Dictionary.DICTIONARY_HARDCODED,
@@ -88,11 +92,11 @@ public final class SpacingAndPunctuations {
}
public boolean isWordSeparator(final int code) {
- return mWordSeparators.contains(String.valueOf((char)code));
+ return Arrays.binarySearch(mSortedWordSeparators, code) >= 0;
}
public boolean isWordConnector(final int code) {
- return Arrays.binarySearch(mWordConnectors, code) >= 0;
+ return Arrays.binarySearch(mSortedWordConnectors, code) >= 0;
}
public boolean isWordCodePoint(final int code) {
@@ -100,11 +104,11 @@ public final class SpacingAndPunctuations {
}
public boolean isUsuallyPrecededBySpace(final int code) {
- return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0;
+ return Arrays.binarySearch(mSortedSymbolsPrecededBySpace, code) >= 0;
}
public boolean isUsuallyFollowedBySpace(final int code) {
- return Arrays.binarySearch(mSymbolsFollowedBySpace, code) >= 0;
+ return Arrays.binarySearch(mSortedSymbolsFollowedBySpace, code) >= 0;
}
public boolean isSentenceSeparator(final int code) {
diff --git a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
index 057e332e9..702688f93 100644
--- a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
@@ -139,6 +139,20 @@ public final class CapsModeUtils {
j--;
}
if (j <= 0 || Character.isWhitespace(prevChar)) {
+ if (spacingAndPunctuations.mUsesGermanRules) {
+ // In German typography rules, there is a specific case that the first character
+ // of a new line should not be capitalized if the previous line ends in a comma.
+ boolean hasNewLine = false;
+ while (--j >= 0 && Character.isWhitespace(prevChar)) {
+ if (Constants.CODE_ENTER == prevChar) {
+ hasNewLine = true;
+ }
+ prevChar = cs.charAt(j);
+ }
+ if (Constants.CODE_COMMA == prevChar && hasNewLine) {
+ return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & reqModes;
+ }
+ }
// There are only spacing chars between the start of the paragraph and the cursor,
// defined as a isWhitespace() char that is neither a isSpaceChar() nor a tab. Both
// MODE_WORDS and MODE_SENTENCES should be active.
diff --git a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java
index 0f5cd80db..4521ec531 100644
--- a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java
+++ b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java
@@ -37,12 +37,12 @@ public class RecapitalizeStatus {
CAPS_MODE_ALL_UPPER
};
- private static final int getStringMode(final String string, final String separators) {
+ private static final int getStringMode(final String string, final int[] sortedSeparators) {
if (StringUtils.isIdenticalAfterUpcase(string)) {
return CAPS_MODE_ALL_UPPER;
} else if (StringUtils.isIdenticalAfterDowncase(string)) {
return CAPS_MODE_ALL_LOWER;
- } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string, separators)) {
+ } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string, sortedSeparators)) {
return CAPS_MODE_FIRST_WORD_UPPER;
} else {
return CAPS_MODE_ORIGINAL_MIXED_CASE;
@@ -60,26 +60,28 @@ public class RecapitalizeStatus {
private int mRotationStyleCurrentIndex;
private boolean mSkipOriginalMixedCaseMode;
private Locale mLocale;
- private String mSeparators;
+ private int[] mSortedSeparators;
private String mStringAfter;
private boolean mIsActive;
+ private static final int[] EMPTY_STORTED_SEPARATORS = {};
+
public RecapitalizeStatus() {
// By default, initialize with dummy values that won't match any real recapitalize.
- initialize(-1, -1, "", Locale.getDefault(), "");
+ initialize(-1, -1, "", Locale.getDefault(), EMPTY_STORTED_SEPARATORS);
deactivate();
}
public void initialize(final int cursorStart, final int cursorEnd, final String string,
- final Locale locale, final String separators) {
+ final Locale locale, final int[] sortedSeparators) {
mCursorStartBefore = cursorStart;
mStringBefore = string;
mCursorStartAfter = cursorStart;
mCursorEndAfter = cursorEnd;
mStringAfter = string;
- final int initialMode = getStringMode(mStringBefore, separators);
+ final int initialMode = getStringMode(mStringBefore, sortedSeparators);
mLocale = locale;
- mSeparators = separators;
+ mSortedSeparators = sortedSeparators;
if (CAPS_MODE_ORIGINAL_MIXED_CASE == initialMode) {
mRotationStyleCurrentIndex = 0;
mSkipOriginalMixedCaseMode = false;
@@ -131,7 +133,7 @@ public class RecapitalizeStatus {
mStringAfter = mStringBefore.toLowerCase(mLocale);
break;
case CAPS_MODE_FIRST_WORD_UPPER:
- mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSeparators,
+ mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSortedSeparators,
mLocale);
break;
case CAPS_MODE_ALL_UPPER:
diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index c5ed39310..5920c68f1 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -22,6 +22,7 @@ import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Locale;
public final class StringUtils {
@@ -183,6 +184,12 @@ public final class StringUtils {
return codePoints;
}
+ public static int[] toSortedCodePointArray(final String string) {
+ final int[] codePoints = toCodePointArray(string);
+ Arrays.sort(codePoints);
+ return codePoints;
+ }
+
// This method assumes the text is not null. For the empty string, it returns CAPITALIZE_NONE.
public static int getCapitalizationType(final String text) {
// If the first char is not uppercase, then the word is either all lower case or
@@ -265,39 +272,39 @@ public final class StringUtils {
}
public static boolean isIdenticalAfterCapitalizeEachWord(final String text,
- final String separators) {
- boolean needCapsNext = true;
+ final int[] sortedSeparators) {
+ boolean needsCapsNext = true;
final int len = text.length();
for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) {
final int codePoint = text.codePointAt(i);
if (Character.isLetter(codePoint)) {
- if ((needCapsNext && !Character.isUpperCase(codePoint))
- || (!needCapsNext && !Character.isLowerCase(codePoint))) {
+ if ((needsCapsNext && !Character.isUpperCase(codePoint))
+ || (!needsCapsNext && !Character.isLowerCase(codePoint))) {
return false;
}
}
// We need a capital letter next if this is a separator.
- needCapsNext = (-1 != separators.indexOf(codePoint));
+ needsCapsNext = (Arrays.binarySearch(sortedSeparators, codePoint) >= 0);
}
return true;
}
// TODO: like capitalizeFirst*, this does not work perfectly for Dutch because of the IJ digraph
// which should be capitalized together in *some* cases.
- public static String capitalizeEachWord(final String text, final String separators,
+ public static String capitalizeEachWord(final String text, final int[] sortedSeparators,
final Locale locale) {
final StringBuilder builder = new StringBuilder();
- boolean needCapsNext = true;
+ boolean needsCapsNext = true;
final int len = text.length();
for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) {
final String nextChar = text.substring(i, text.offsetByCodePoints(i, 1));
- if (needCapsNext) {
+ if (needsCapsNext) {
builder.append(nextChar.toUpperCase(locale));
} else {
builder.append(nextChar.toLowerCase(locale));
}
// We need a capital letter next if this is a separator.
- needCapsNext = (-1 != separators.indexOf(nextChar.codePointAt(0)));
+ needsCapsNext = (Arrays.binarySearch(sortedSeparators, nextChar.codePointAt(0)) >= 0);
}
return builder.toString();
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index e7f49a605..11fb3a156 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -59,6 +59,7 @@ import com.android.inputmethod.latin.RichInputConnection;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.utils.InputTypeUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
import com.android.inputmethod.latin.utils.TextRange;
import com.android.inputmethod.research.MotionEventReader.ReplayData;
import com.android.inputmethod.research.ui.SplashScreen;
@@ -131,7 +132,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static final String RESEARCH_KEY_OUTPUT_TEXT = ".research.";
// constants related to specific log points
- private static final String WHITESPACE_SEPARATORS = " \t\n\r";
+ private static final int[] WHITESPACE_SEPARATORS =
+ StringUtils.toSortedCodePointArray(" \t\n\r");
private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1
private static final String PREF_RESEARCH_SAVED_CHANNEL = "pref_research_saved_channel";