aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/values/strings-config-important-notice.xml13
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java5
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java23
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java25
-rw-r--r--java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java78
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java49
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java6
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java2
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java28
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java26
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java28
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp13
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp15
-rw-r--r--tests/src/com/android/inputmethod/latin/InputLogicTests.java32
-rw-r--r--tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java78
-rw-r--r--tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl (renamed from tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl)5
-rw-r--r--tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java1
17 files changed, 323 insertions, 104 deletions
diff --git a/java/res/values/strings-config-important-notice.xml b/java/res/values/strings-config-important-notice.xml
index 3be95d333..f2229bec4 100644
--- a/java/res/values/strings-config-important-notice.xml
+++ b/java/res/values/strings-config-important-notice.xml
@@ -20,11 +20,14 @@
<resources>
<integer name="config_important_notice_version">0</integer>
- <!-- TODO: Make title and contents resource to string array indexed by version. -->
- <!-- The text of the important notice displayed on the suggestion strip. -->
- <string name="important_notice_title"></string>
- <!-- The contents of the important notice. -->
- <string name="important_notice_contents"></string>
+ <!-- The array of the text of the important notices displayed on the suggestion strip. -->
+ <string-array name="important_notice_title_array">
+ <!-- empty -->
+ </string-array>
+ <!-- The array of the contents of the important notices. -->
+ <string-array name="important_notice_contents_array">
+ <!-- empty -->
+ </string-array>
<!-- Description for option enabling the use by the keyboards of sent/received messages, e-mail and typing history to improve suggestion accuracy [CHAR LIMIT=68] -->
<string name="use_personalized_dicts_summary">Learn from your communications and typed data to improve suggestions</string>
</resources>
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
index 93d80c909..96acb1551 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
@@ -24,7 +24,8 @@ import java.util.HashMap;
* !!!!! DO NOT EDIT THIS FILE !!!!!
*
* This file is generated by tools/make-keyboard-text. The base template file is
- * tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl
+ * tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/
+ * KeyboardTextsTable.tmpl
*
* This file must be updated when any text resources in keyboard layout files have been changed.
* These text resources are referred as "!text/<resource_name>" in keyboard XML definitions,
@@ -34,7 +35,7 @@ import java.util.HashMap;
* To update this file, please run the following commands.
* $ cd $ANDROID_BUILD_TOP
* $ mmm packages/inputmethods/LatinIME/tools/make-keyboard-text
- * $ make-keyboard-text -java packages/inputmethods/LatinIME/java/src
+ * $ make-keyboard-text -java packages/inputmethods/LatinIME/java
*
* The updated source file will be generated to the following path (this file).
* packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 013f9220a..c450a1d4f 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -17,6 +17,7 @@
package com.android.inputmethod.latin;
import android.text.TextUtils;
+import android.util.Log;
import android.util.SparseArray;
import com.android.inputmethod.annotations.UsedForTesting;
@@ -29,6 +30,7 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.makedict.WordProperty;
import com.android.inputmethod.latin.settings.NativeSuggestOptions;
import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.FileUtils;
import com.android.inputmethod.latin.utils.JniUtils;
import com.android.inputmethod.latin.utils.LanguageModelParam;
import com.android.inputmethod.latin.utils.StringUtils;
@@ -84,6 +86,7 @@ public final class BinaryDictionary extends Dictionary {
private final Locale mLocale;
private final long mDictSize;
private final String mDictFilePath;
+ private final boolean mIsUpdatable;
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_RESULTS];
@@ -130,6 +133,7 @@ public final class BinaryDictionary extends Dictionary {
mLocale = locale;
mDictSize = length;
mDictFilePath = filename;
+ mIsUpdatable = isUpdatable;
mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance);
loadDictionary(filename, offset, length, isUpdatable);
}
@@ -177,6 +181,7 @@ public final class BinaryDictionary extends Dictionary {
int bigramProbability);
private static native int setCurrentTimeForTestNative(int currentTime);
private static native String getPropertyNative(long dict, String query);
+ private static native boolean isCorruptedNative(long dict);
public static boolean createEmptyDictFile(final String filePath, final long dictVersion,
final Locale locale, final Map<String, String> attributeMap) {
@@ -198,6 +203,22 @@ public final class BinaryDictionary extends Dictionary {
mNativeDict = openNative(path, startOffset, length, isUpdatable);
}
+ // TODO: Check isCorrupted() for main dictionaries.
+ public boolean isCorrupted() {
+ if (!isValidDictionary()) {
+ return false;
+ }
+ if (!isCorruptedNative(mNativeDict)) {
+ return false;
+ }
+ // TODO: Record the corruption.
+ Log.e(TAG, "BinaryDictionary (" + mDictFilePath + ") is corrupted.");
+ Log.e(TAG, "locale: " + mLocale);
+ Log.e(TAG, "dict size: " + mDictSize);
+ Log.e(TAG, "updatable: " + mIsUpdatable);
+ return true;
+ }
+
@UsedForTesting
public DictionaryHeader getHeader() throws UnsupportedFormatException {
if (mNativeDict == 0) {
@@ -444,7 +465,7 @@ public final class BinaryDictionary extends Dictionary {
// only be called for actual files. Right now it's only called by the flush() family of
// functions, which require an updatable dictionary, so it's okay. But beware.
loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */,
- dictFile.length(), true /* isUpdatable */);
+ dictFile.length(), mIsUpdatable);
}
public void flush() {
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 230739d6f..f9ab9419b 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -276,22 +276,26 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return attributeMap;
}
+ private void removeBinaryDictionaryLocked() {
+ if (mBinaryDictionary != null) {
+ mBinaryDictionary.close();
+ }
+ if (mDictFile.exists() && !FileUtils.deleteRecursively(mDictFile)) {
+ Log.e(TAG, "Can't remove a file: " + mDictFile.getName());
+ }
+ mBinaryDictionary = null;
+ }
+
protected void clear() {
- final File dictFile = mDictFile;
getExecutor(mDictName).execute(new Runnable() {
@Override
public void run() {
if (mDictionaryWriter == null) {
- if (mBinaryDictionary != null) {
- mBinaryDictionary.close();
- }
- if (dictFile.exists() && !FileUtils.deleteRecursively(dictFile)) {
- Log.e(TAG, "Can't remove a file: " + dictFile.getName());
- }
- BinaryDictionary.createEmptyDictFile(dictFile.getAbsolutePath(),
+ removeBinaryDictionaryLocked();
+ BinaryDictionary.createEmptyDictFile(mDictFile.getAbsolutePath(),
DICTIONARY_FORMAT_VERSION, mLocale, getHeaderAttributeMap());
mBinaryDictionary = new BinaryDictionary(
- dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(),
+ mDictFile.getAbsolutePath(), 0 /* offset */, mDictFile.length(),
true /* useFullEditDistance */, mLocale, mDictType, mIsUpdatable);
} else {
mDictionaryWriter.clear();
@@ -469,6 +473,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
proximityInfo, blockOffensiveWords, additionalFeaturesOptions,
sessionId);
holder.set(binarySuggestion);
+ if (mBinaryDictionary.isCorrupted()) {
+ removeBinaryDictionaryLocked();
+ }
}
});
return holder.get(null, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS);
diff --git a/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java b/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java
new file mode 100644
index 000000000..9870faa98
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnDismissListener;
+import android.content.DialogInterface.OnShowListener;
+
+import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
+
+/**
+ * The dialog box that shows the important notice contents.
+ */
+public final class ImportantNoticeDialog extends AlertDialog implements OnShowListener,
+ OnClickListener, OnDismissListener {
+ public interface ImportantNoticeDialogListener {
+ public void onClickSettingsOfImportantNoticeDialog(final int nextVersion);
+ public void onDismissImportantNoticeDialog(final int nextVersion);
+ }
+
+ private final ImportantNoticeDialogListener mListener;
+ private final int mNextImportantNoticeVersion;
+
+ public ImportantNoticeDialog(
+ final Context context, final ImportantNoticeDialogListener listener) {
+ super(context, THEME_HOLO_DARK);
+ mListener = listener;
+ mNextImportantNoticeVersion = ImportantNoticeUtils.getNextImportantNoticeVersion(context);
+ setMessage(ImportantNoticeUtils.getNextImportantNoticeContents(context));
+ // Create buttons and set listeners.
+ setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok), this);
+ if (shouldHaveSettingsButton()) {
+ setButton(BUTTON_NEGATIVE, context.getString(R.string.go_to_settings), this);
+ }
+ // Set listeners.
+ setOnShowListener(this);
+ setOnDismissListener(this);
+ }
+
+ private boolean shouldHaveSettingsButton() {
+ return mNextImportantNoticeVersion
+ == ImportantNoticeUtils.VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS;
+ }
+
+ @Override
+ public void onShow(final DialogInterface dialog) {
+ ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext());
+ }
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ if (shouldHaveSettingsButton() && which == BUTTON_NEGATIVE) {
+ mListener.onClickSettingsOfImportantNoticeDialog(mNextImportantNoticeVersion);
+ }
+ }
+
+ @Override
+ public void onDismiss(final DialogInterface dialog) {
+ mListener.onDismissImportantNoticeDialog(mNextImportantNoticeVersion);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 47137e7fb..44282a492 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -26,8 +26,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.DialogInterface.OnShowListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
@@ -100,7 +98,8 @@ import java.util.concurrent.TimeUnit;
*/
public class LatinIME extends InputMethodService implements KeyboardActionListener,
SuggestionStripView.Listener, SuggestionStripViewAccessor,
- DictionaryFacilitatorForSuggest.DictionaryInitializationListener {
+ DictionaryFacilitatorForSuggest.DictionaryInitializationListener,
+ ImportantNoticeDialog.ImportantNoticeDialogListener {
private static final String TAG = LatinIME.class.getSimpleName();
private static final boolean TRACE = false;
private static boolean DEBUG = false;
@@ -751,6 +750,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ ", word caps = "
+ ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0));
}
+ Log.i(TAG, "Starting input. Cursor position = "
+ + editorInfo.initialSelStart + "," + editorInfo.initialSelEnd);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs);
@@ -1180,39 +1181,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mInputLogic.mSuggest.mDictionaryFacilitator.addWordToUserDictionary(wordToEdit);
}
- // TODO: Move this method out of {@link LatinIME}.
// Callback for the {@link SuggestionStripView}, to call when the important notice strip is
// pressed.
@Override
public void showImportantNoticeContents() {
- final Context context = this;
- final AlertDialog.Builder builder =
- new AlertDialog.Builder(context, AlertDialog.THEME_HOLO_DARK);
- builder.setMessage(ImportantNoticeUtils.getNextImportantNoticeContents(context));
- builder.setPositiveButton(android.R.string.ok, null /* listener */);
- final OnClickListener onClickListener = new OnClickListener() {
- @Override
- public void onClick(final DialogInterface dialog, final int position) {
- if (position == DialogInterface.BUTTON_NEGATIVE) {
- launchSettings();
- }
- }
- };
- builder.setNegativeButton(R.string.go_to_settings, onClickListener);
- final AlertDialog importantNoticeDialog = builder.create();
- importantNoticeDialog.setOnShowListener(new OnShowListener() {
- @Override
- public void onShow(final DialogInterface dialog) {
- ImportantNoticeUtils.updateLastImportantNoticeVersion(context);
- }
- });
- importantNoticeDialog.setOnDismissListener(new OnDismissListener() {
- @Override
- public void onDismiss(final DialogInterface dialog) {
- setNeutralSuggestionStrip();
- }
- });
- showOptionDialog(importantNoticeDialog);
+ showOptionDialog(new ImportantNoticeDialog(this /* context */, this /* listener */));
+ }
+
+ // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener}
+ @Override
+ public void onClickSettingsOfImportantNoticeDialog(final int nextVersion) {
+ launchSettings();
+ }
+
+ // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener}
+ @Override
+ public void onDismissImportantNoticeDialog(final int nextVersion) {
+ setNeutralSuggestionStrip();
}
public void displaySettingsDialog() {
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 0e85b3c77..30b20a335 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -847,9 +847,9 @@ public final class RichInputConnection {
mExpectedSelStart = mExpectedSelEnd = Constants.NOT_A_CURSOR_POSITION;
} else {
final int textLength = textBeforeCursor.length();
- if (textLength > mExpectedSelStart
- || (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE
- && mExpectedSelStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) {
+ if (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE
+ && (textLength > mExpectedSelStart
+ || mExpectedSelStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) {
// It should not be possible to have only one of those variables be
// NOT_A_CURSOR_POSITION, so if they are equal, either the selection is zero-sized
// (simple cursor, no selection) or there is no cursor/we don't know its pos
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index eeb5bf536..045d06f0e 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -490,6 +490,7 @@ public final class InputLogic {
handler.showGesturePreviewAndSuggestionStrip(
SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */);
handler.cancelUpdateSuggestionStrip();
+ ++mAutoCommitSequenceNumber;
mConnection.beginBatchEdit();
if (mWordComposer.isComposingWord()) {
if (settingsValues.mIsInternal) {
@@ -587,6 +588,7 @@ public final class InputLogic {
public void onEndBatchInput(final SettingsValues settingValues,
final InputPointers batchPointers) {
mInputLogicHandler.onEndBatchInput(batchPointers, mAutoCommitSequenceNumber);
+ ++mAutoCommitSequenceNumber;
}
// TODO: remove this argument
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java
index 71e120c5f..bf776cfc5 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java
@@ -120,16 +120,10 @@ public class Ver2DictDecoder extends AbstractDictDecoder {
// used only for testing.
private final DictionaryBufferFactory mBufferFactory;
protected DictBuffer mDictBuffer;
- private final BinaryDictionary mBinaryDictionary;
/* package */ Ver2DictDecoder(final File file, final int factoryFlag) {
mDictionaryBinaryFile = file;
mDictBuffer = null;
- // dictType is not being used in dicttool. Passing an empty string.
- mBinaryDictionary = new BinaryDictionary(file.getAbsolutePath(),
- 0 /* offset */, file.length() /* length */, true /* useFullEditDistance */,
- null /* locale */, "" /* dictType */, false /* isUpdatable */);
-
if ((factoryFlag & MASK_DICTBUFFER) == USE_READONLY_BYTEBUFFER) {
mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory();
} else if ((factoryFlag & MASK_DICTBUFFER) == USE_BYTEARRAY) {
@@ -144,10 +138,6 @@ public class Ver2DictDecoder extends AbstractDictDecoder {
/* package */ Ver2DictDecoder(final File file, final DictionaryBufferFactory factory) {
mDictionaryBinaryFile = file;
mBufferFactory = factory;
- // dictType is not being used in dicttool. Passing an empty string.
- mBinaryDictionary = new BinaryDictionary(file.getAbsolutePath(),
- 0 /* offset */, file.length() /* length */, true /* useFullEditDistance */,
- null /* locale */, "" /* dictType */, false /* isUpdatable */);
}
@Override
@@ -172,7 +162,13 @@ public class Ver2DictDecoder extends AbstractDictDecoder {
@Override
public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException {
- final DictionaryHeader header = mBinaryDictionary.getHeader();
+ // dictType is not being used in dicttool. Passing an empty string.
+ final BinaryDictionary binaryDictionary = new BinaryDictionary(
+ mDictionaryBinaryFile.getAbsolutePath(), 0 /* offset */,
+ mDictionaryBinaryFile.length() /* length */, true /* useFullEditDistance */,
+ null /* locale */, "" /* dictType */, false /* isUpdatable */);
+ final DictionaryHeader header = binaryDictionary.getHeader();
+ binaryDictionary.close();
if (header == null) {
throw new IOException("Cannot read the dictionary header.");
}
@@ -254,6 +250,11 @@ public class Ver2DictDecoder extends AbstractDictDecoder {
@Override
public FusionDictionary readDictionaryBinary(final boolean deleteDictIfBroken)
throws FileNotFoundException, IOException, UnsupportedFormatException {
+ // dictType is not being used in dicttool. Passing an empty string.
+ final BinaryDictionary binaryDictionary = new BinaryDictionary(
+ mDictionaryBinaryFile.getAbsolutePath(), 0 /* offset */,
+ mDictionaryBinaryFile.length() /* length */, true /* useFullEditDistance */,
+ null /* locale */, "" /* dictType */, false /* isUpdatable */);
final DictionaryHeader header = readHeader();
final FusionDictionary fusionDict =
new FusionDictionary(new FusionDictionary.PtNodeArray(), header.mDictionaryOptions);
@@ -261,11 +262,11 @@ public class Ver2DictDecoder extends AbstractDictDecoder {
final ArrayList<WordProperty> wordProperties = CollectionUtils.newArrayList();
do {
final BinaryDictionary.GetNextWordPropertyResult result =
- mBinaryDictionary.getNextWordProperty(token);
+ binaryDictionary.getNextWordProperty(token);
final WordProperty wordProperty = result.mWordProperty;
if (wordProperty == null) {
+ binaryDictionary.close();
if (deleteDictIfBroken) {
- mBinaryDictionary.close();
mDictionaryBinaryFile.delete();
}
return null;
@@ -294,6 +295,7 @@ public class Ver2DictDecoder extends AbstractDictDecoder {
fusionDict.setBigram(word0, bigram.mWord, bigram.mProbabilityInfo);
}
}
+ binaryDictionary.close();
return fusionDict;
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
index 88fff38f2..afe82317e 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
@@ -35,7 +35,6 @@ public class Ver4DictDecoder extends AbstractDictDecoder {
private static final String TAG = Ver4DictDecoder.class.getSimpleName();
final File mDictDirectory;
- final BinaryDictionary mBinaryDictionary;
@UsedForTesting
/* package */ Ver4DictDecoder(final File dictDirectory, final int factoryFlag) {
@@ -45,24 +44,32 @@ public class Ver4DictDecoder extends AbstractDictDecoder {
@UsedForTesting
/* package */ Ver4DictDecoder(final File dictDirectory, final DictionaryBufferFactory factory) {
mDictDirectory = dictDirectory;
- // dictType is not being used in dicttool. Passing an empty string.
- mBinaryDictionary = new BinaryDictionary(dictDirectory.getAbsolutePath(),
- 0 /* offset */, 0 /* length */, true /* useFullEditDistance */, null /* locale */,
- "" /* dictType */, true /* isUpdatable */);
+
}
@Override
public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException {
- final DictionaryHeader header = mBinaryDictionary.getHeader();
+ // dictType is not being used in dicttool. Passing an empty string.
+ final BinaryDictionary binaryDictionary= new BinaryDictionary(
+ mDictDirectory.getAbsolutePath(), 0 /* offset */, 0 /* length */,
+ true /* useFullEditDistance */, null /* locale */,
+ "" /* dictType */, true /* isUpdatable */);
+ final DictionaryHeader header = binaryDictionary.getHeader();
+ binaryDictionary.close();
if (header == null) {
throw new IOException("Cannot read the dictionary header.");
}
- return mBinaryDictionary.getHeader();
+ return header;
}
@Override
public FusionDictionary readDictionaryBinary(final boolean deleteDictIfBroken)
throws FileNotFoundException, IOException, UnsupportedFormatException {
+ // dictType is not being used in dicttool. Passing an empty string.
+ final BinaryDictionary binaryDictionary = new BinaryDictionary(
+ mDictDirectory.getAbsolutePath(), 0 /* offset */, 0 /* length */,
+ true /* useFullEditDistance */, null /* locale */,
+ "" /* dictType */, true /* isUpdatable */);
final DictionaryHeader header = readHeader();
final FusionDictionary fusionDict =
new FusionDictionary(new FusionDictionary.PtNodeArray(), header.mDictionaryOptions);
@@ -70,11 +77,11 @@ public class Ver4DictDecoder extends AbstractDictDecoder {
final ArrayList<WordProperty> wordProperties = CollectionUtils.newArrayList();
do {
final BinaryDictionary.GetNextWordPropertyResult result =
- mBinaryDictionary.getNextWordProperty(token);
+ binaryDictionary.getNextWordProperty(token);
final WordProperty wordProperty = result.mWordProperty;
if (wordProperty == null) {
+ binaryDictionary.close();
if (deleteDictIfBroken) {
- mBinaryDictionary.close();
FileUtils.deleteRecursively(mDictDirectory);
}
return null;
@@ -103,6 +110,7 @@ public class Ver4DictDecoder extends AbstractDictDecoder {
fusionDict.setBigram(word0, bigram.mWord, bigram.mProbabilityInfo);
}
}
+ binaryDictionary.close();
return fusionDict;
}
}
diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
index 6b0bb86ac..ca8bef397 100644
--- a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
@@ -60,7 +60,7 @@ public final class ImportantNoticeUtils {
return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
}
- public static int getCurrentImportantNoticeVersion(final Context context) {
+ private static int getCurrentImportantNoticeVersion(final Context context) {
return context.getResources().getInteger(R.integer.config_important_notice_version);
}
@@ -68,7 +68,7 @@ public final class ImportantNoticeUtils {
return getImportantNoticePreferences(context).getInt(KEY_IMPORTANT_NOTICE_VERSION, 0);
}
- private static int getNextImportantNoticeVersion(final Context context) {
+ public static int getNextImportantNoticeVersion(final Context context) {
return getLastImportantNoticeVersion(context) + 1;
}
@@ -92,23 +92,23 @@ public final class ImportantNoticeUtils {
.apply();
}
- // TODO: Make title resource to string array indexed by version.
public static String getNextImportantNoticeTitle(final Context context) {
- switch (getNextImportantNoticeVersion(context)) {
- case VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS:
- return context.getString(R.string.important_notice_title);
- default:
- return null;
+ final int nextVersion = getCurrentImportantNoticeVersion(context);
+ final String[] importantNoticeTitleArray = context.getResources().getStringArray(
+ R.array.important_notice_title_array);
+ if (nextVersion > 0 && nextVersion < importantNoticeTitleArray.length) {
+ return importantNoticeTitleArray[nextVersion];
}
+ return null;
}
- // TODO: Make content resource to string array indexed by version.
public static String getNextImportantNoticeContents(final Context context) {
- switch (getNextImportantNoticeVersion(context)) {
- case VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS:
- return context.getString(R.string.important_notice_contents);
- default:
- return null;
+ final int nextVersion = getNextImportantNoticeVersion(context);
+ final String[] importantNoticeContentsArray = context.getResources().getStringArray(
+ R.array.important_notice_contents_array);
+ if (nextVersion > 0 && nextVersion < importantNoticeContentsArray.length) {
+ return importantNoticeContentsArray[nextVersion];
}
+ return null;
}
}
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 1e00cd825..bb54cbdb9 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -529,6 +529,14 @@ static int latinime_BinaryDictionary_setCurrentTimeForTest(JNIEnv *env, jclass c
return TimeKeeper::peekCurrentTime();
}
+static bool latinime_BinaryDictionary_isCorruptedNative(JNIEnv *env, jclass clazz, jlong dict) {
+ Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
+ if (!dictionary) {
+ return false;
+ }
+ return dictionary->getDictionaryStructurePolicy()->isCorrupted();
+}
+
static const JNINativeMethod sMethods[] = {
{
const_cast<char *>("createEmptyDictFileNative"),
@@ -642,6 +650,11 @@ static const JNINativeMethod sMethods[] = {
const_cast<char *>("getPropertyNative"),
const_cast<char *>("(JLjava/lang/String;)Ljava/lang/String;"),
reinterpret_cast<void *>(latinime_BinaryDictionary_getProperty)
+ },
+ {
+ const_cast<char *>("isCorruptedNative"),
+ const_cast<char *>("(J)Z"),
+ reinterpret_cast<void *>(latinime_BinaryDictionary_isCorruptedNative)
}
};
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
index 212f2ef39..84a6ccf33 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
@@ -87,9 +87,24 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
int lastCandidatePtNodePos = 0;
// Let's loop through PtNodes in this PtNode array searching for either the terminal
// or one of its ascendants.
+ if (pos < 0 || pos >= mDictBufferSize) {
+ AKLOGE("PtNode array position is invalid. pos: %d, dict size: %d",
+ pos, mDictBufferSize);
+ mIsCorrupted = true;
+ ASSERT(false);
+ *outUnigramProbability = NOT_A_PROBABILITY;
+ return 0;
+ }
for (int ptNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
mDictRoot, &pos); ptNodeCount > 0; --ptNodeCount) {
const int startPos = pos;
+ if (pos < 0 || pos >= mDictBufferSize) {
+ AKLOGE("PtNode position is invalid. pos: %d, dict size: %d", pos, mDictBufferSize);
+ mIsCorrupted = true;
+ ASSERT(false);
+ *outUnigramProbability = NOT_A_PROBABILITY;
+ return 0;
+ }
const PatriciaTrieReadingUtils::NodeFlags flags =
PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
const int character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index 1c714e7de..ab9751380 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -351,6 +351,38 @@ public class InputLogicTests extends InputTestsBase {
}
// TODO: Add some tests for non-BMP characters
+ public void testAutoCorrectByUserHistory() {
+ final String WORD_TO_BE_CORRECTED = "qpmx";
+ final String NOT_CORRECTED_RESULT = "qpmx ";
+ final String DESIRED_WORD = "qpmz";
+ final String CORRECTED_RESULT = "qpmz ";
+ final int typeCountNotToAutocorrect = 3;
+ final int typeCountToAutoCorrect = 16;
+ int startIndex = 0;
+ int endIndex = 0;
+
+ for (int i = 0; i < typeCountNotToAutocorrect; i++) {
+ type(DESIRED_WORD);
+ type(Constants.CODE_SPACE);
+ }
+ startIndex = mEditText.getText().length();
+ type(WORD_TO_BE_CORRECTED);
+ type(Constants.CODE_SPACE);
+ endIndex = mEditText.getText().length();
+ assertEquals("not auto-corrected by user history", NOT_CORRECTED_RESULT,
+ mEditText.getText().subSequence(startIndex, endIndex).toString());
+ for (int i = typeCountNotToAutocorrect; i < typeCountToAutoCorrect; i++) {
+ type(DESIRED_WORD);
+ type(Constants.CODE_SPACE);
+ }
+ startIndex = mEditText.getText().length();
+ type(WORD_TO_BE_CORRECTED);
+ type(Constants.CODE_SPACE);
+ endIndex = mEditText.getText().length();
+ assertEquals("auto-corrected by user history",
+ CORRECTED_RESULT, mEditText.getText().subSequence(startIndex, endIndex).toString());
+ }
+
public void testPredictionsAfterSpace() {
final String WORD_TO_TYPE = "Barack ";
type(WORD_TO_TYPE);
diff --git a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
index 24af09484..2cc22fae4 100644
--- a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
+++ b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
@@ -20,6 +20,8 @@ import android.content.res.Resources;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.utils.RunInLocale;
@@ -32,6 +34,18 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase {
private static final int ARMENIAN_FULL_STOP = '\u0589';
private static final int ARMENIAN_COMMA = '\u055D';
+ private int mScreenMetrics;
+
+ private boolean isPhone() {
+ return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_PHONE
+ || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_PHONE;
+ }
+
+ private boolean isTablet() {
+ return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_TABLET
+ || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_TABLET;
+ }
+
private SpacingAndPunctuations ENGLISH;
private SpacingAndPunctuations FRENCH;
private SpacingAndPunctuations GERMAN;
@@ -56,6 +70,8 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase {
protected void setUp() throws Exception {
super.setUp();
+ mScreenMetrics = mContext.getResources().getInteger(R.integer.config_screen_metrics);
+
// Language only
ENGLISH = getSpacingAndPunctuations(Locale.ENGLISH);
FRENCH = getSpacingAndPunctuations(Locale.FRENCH);
@@ -373,23 +389,39 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase {
assertTrue(SWISS_GERMAN.mUsesGermanRules);
}
- private static final String[] PUNCTUATION_LABELS_LTR = {
+ // Punctuations for phone.
+ private static final String[] PUNCTUATION_LABELS_PHONE = {
"!", "?", ",", ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_"
};
- private static final String[] PUNCTUATION_WORDS_LTR = PUNCTUATION_LABELS_LTR;
- private static final String[] PUNCTUATION_WORDS_HEBREW = {
+ private static final String[] PUNCTUATION_WORDS_PHONE_LTR = PUNCTUATION_LABELS_PHONE;
+ private static final String[] PUNCTUATION_WORDS_PHONE_HEBREW = {
"!", "?", ",", ":", ";", "\"", ")", "(", "'", "-", "/", "@", "_"
};
// U+061F: "؟" ARABIC QUESTION MARK
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
- private static final String[] PUNCTUATION_LABELS_ARABIC_PERSIAN = {
+ private static final String[] PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN = {
"!", "\u061F", "\u060C", ":", "\u061B", "\"", "(", ")", "'", "-", "/", "@", "_"
};
- private static final String[] PUNCTUATION_WORDS_ARABIC_PERSIAN = {
+ private static final String[] PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN = {
"!", "\u061F", "\u060C", ":", "\u061B", "\"", ")", "(", "'", "-", "/", "@", "_"
};
+ // Punctuations for tablet.
+ private static final String[] PUNCTUATION_LABELS_TABLET = {
+ ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_"
+ };
+ private static final String[] PUNCTUATION_WORDS_TABLET_LTR = PUNCTUATION_LABELS_TABLET;
+ private static final String[] PUNCTUATION_WORDS_TABLET_HEBREW = {
+ ":", ";", "\"", ")", "(", "'", "-", "/", "@", "_"
+ };
+ private static final String[] PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN = {
+ "!", "\u061F", ":", "\u061B", "\"", "'", "(", ")", "-", "/", "@", "_"
+ };
+ private static final String[] PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN = {
+ "!", "\u061F", ":", "\u061B", "\"", "'", ")", "(", "-", "/", "@", "_"
+ };
+
private static void testingStandardPunctuationSuggestions(final SpacingAndPunctuations sp,
final String[] punctuationLabels, final String[] punctuationWords) {
final SuggestedWords suggestedWords = sp.mSuggestPuncList;
@@ -407,19 +439,39 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase {
}
}
- // TODO: Add tests for tablet as well
- public void testPunctuationSuggestions() {
+ public void testPhonePunctuationSuggestions() {
+ if (!isPhone()) {
+ return;
+ }
+ testingStandardPunctuationSuggestions(ENGLISH,
+ PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR);
+ testingStandardPunctuationSuggestions(FRENCH,
+ PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR);
+ testingStandardPunctuationSuggestions(GERMAN,
+ PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR);
+ testingStandardPunctuationSuggestions(ARABIC,
+ PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN, PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN);
+ testingStandardPunctuationSuggestions(PERSIAN,
+ PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN, PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN);
+ testingStandardPunctuationSuggestions(HEBREW,
+ PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_HEBREW);
+ }
+
+ public void testTabletPunctuationSuggestions() {
+ if (!isTablet()) {
+ return;
+ }
testingStandardPunctuationSuggestions(ENGLISH,
- PUNCTUATION_LABELS_LTR, PUNCTUATION_WORDS_LTR);
+ PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR);
testingStandardPunctuationSuggestions(FRENCH,
- PUNCTUATION_LABELS_LTR, PUNCTUATION_WORDS_LTR);
+ PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR);
testingStandardPunctuationSuggestions(GERMAN,
- PUNCTUATION_LABELS_LTR, PUNCTUATION_WORDS_LTR);
+ PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR);
testingStandardPunctuationSuggestions(ARABIC,
- PUNCTUATION_LABELS_ARABIC_PERSIAN, PUNCTUATION_WORDS_ARABIC_PERSIAN);
+ PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN, PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN);
testingStandardPunctuationSuggestions(PERSIAN,
- PUNCTUATION_LABELS_ARABIC_PERSIAN, PUNCTUATION_WORDS_ARABIC_PERSIAN);
+ PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN, PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN);
testingStandardPunctuationSuggestions(HEBREW,
- PUNCTUATION_LABELS_LTR, PUNCTUATION_WORDS_HEBREW);
+ PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_HEBREW);
}
}
diff --git a/tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl b/tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl
index 7ec42ceea..b25bfb204 100644
--- a/tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl
+++ b/tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl
@@ -24,7 +24,8 @@ import java.util.HashMap;
* !!!!! DO NOT EDIT THIS FILE !!!!!
*
* This file is generated by tools/make-keyboard-text. The base template file is
- * tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl
+ * tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/
+ * KeyboardTextsTable.tmpl
*
* This file must be updated when any text resources in keyboard layout files have been changed.
* These text resources are referred as "!text/<resource_name>" in keyboard XML definitions,
@@ -34,7 +35,7 @@ import java.util.HashMap;
* To update this file, please run the following commands.
* $ cd $ANDROID_BUILD_TOP
* $ mmm packages/inputmethods/LatinIME/tools/make-keyboard-text
- * $ make-keyboard-text -java packages/inputmethods/LatinIME/java/src
+ * $ make-keyboard-text -java packages/inputmethods/LatinIME/java
*
* The updated source file will be generated to the following path (this file).
* packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java
index e9d6c864f..9bb2b38dd 100644
--- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java
@@ -29,7 +29,6 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.jar.JarFile;
-import java.util.regex.Pattern;
public class MoreKeysResources {
private static final String TEXT_RESOURCE_NAME = "donottranslate-more-keys.xml";