diff options
31 files changed, 310 insertions, 249 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index e8a89712c..1400e05c8 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -1008,6 +1008,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int index = me.getActionIndex(); final int id = me.getPointerId(index); final PointerTracker tracker = PointerTracker.getPointerTracker(id); + // When a more keys panel is showing, we should ignore other fingers' single touch events + // other than the finger that is showing the more keys panel. + if (isShowingMoreKeysPanel() && !tracker.isShowingMoreKeysPanel() + && PointerTracker.getActivePointerTrackerCount() == 1) { + return true; + } tracker.processMotionEvent(me, mKeyDetector); return true; } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index ae6aee4a1..f9e78bfd9 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -715,7 +715,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return newKey; } - private static int getActivePointerTrackerCount() { + /* package */ static int getActivePointerTrackerCount() { return sPointerTrackerQueue.size(); } @@ -827,12 +827,19 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final int action = me.getActionMasked(); final long eventTime = me.getEventTime(); if (action == MotionEvent.ACTION_MOVE) { + // When this pointer is the only active pointer and is showing a more keys panel, + // we should ignore other pointers' motion event. + final boolean shouldIgnoreOtherPointers = + isShowingMoreKeysPanel() && getActivePointerTrackerCount() == 1; final int pointerCount = me.getPointerCount(); for (int index = 0; index < pointerCount; index++) { final int id = me.getPointerId(index); - final PointerTracker tracker = getPointerTracker(id); + if (shouldIgnoreOtherPointers && id != mPointerId) { + continue; + } final int x = (int)me.getX(index); final int y = (int)me.getY(index); + final PointerTracker tracker = getPointerTracker(id); tracker.onMoveEvent(x, y, eventTime, me); } return; @@ -903,7 +910,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } - private boolean isShowingMoreKeysPanel() { + /* package */ boolean isShowingMoreKeysPanel() { return (mMoreKeysPanel != null); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java index f0feb2513..e2fd39017 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java @@ -25,7 +25,7 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.utils.JsonUtils; import java.util.ArrayDeque; import java.util.ArrayList; @@ -139,7 +139,7 @@ public class DynamicGridKeyboard extends Keyboard { keys.add(key.getCode()); } } - final String jsonStr = StringUtils.listToJsonStr(keys); + final String jsonStr = JsonUtils.listToJsonStr(keys); Settings.writeEmojiRecentKeys(mPrefs, jsonStr); } @@ -167,7 +167,7 @@ public class DynamicGridKeyboard extends Keyboard { public void loadRecentKeys(final Collection<DynamicGridKeyboard> keyboards) { final String str = Settings.readEmojiRecentKeys(mPrefs); - final List<Object> keys = StringUtils.jsonStrToList(str); + final List<Object> keys = JsonUtils.jsonStrToList(str); for (final Object o : keys) { final Key key; if (o instanceof Integer) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index f1b5bc116..1b722c5ce 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -384,7 +384,8 @@ public final class KeyboardTextsSet { /* 122 */ "w", /* 123 */ "y", /* 124 */ "x", - /* 125 */ EMPTY, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + /* 125 */ "\u00F1", /* 126 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm", /* 127 */ "!icon/settings_key|!code/key_settings", /* 128 */ "!icon/shortcut_key|!code/key_shortcut", @@ -1286,15 +1287,6 @@ public final class KeyboardTextsSet { // U+00A1: "¡" INVERTED EXCLAMATION MARK // U+00BF: "¿" INVERTED QUESTION MARK /* 59 */ "!fixedColumnOrder!9,\u00A1,;,/,(,),#,!,\\,,?,\u00BF,&,\\%,+,\",-,:,',@", - /* 60~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, - /* ~124 */ - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - /* 125 */ "\u00F1", }; /* Language et_EE: Estonian (Estonia) */ diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index b70362f90..b6cfcd064 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -72,7 +72,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private final boolean mUseFirstLastBigrams; public ContactsBinaryDictionary(final Context context, final Locale locale) { - super(context, getFilenameWithLocale(NAME, locale), locale, + super(context, getDictNameWithLocale(NAME, locale), locale, Dictionary.TYPE_CONTACTS, false /* isUpdatable */); mLocale = locale; mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale); diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 5d1c39666..b52045e3c 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -69,14 +69,14 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { /** * A static map of update controllers, each of which records the time of accesses to a single * binary dictionary file and tracks whether the file is regenerating. The key for this map is - * the filename and the value is the shared dictionary time recorder associated with that - * filename. + * the dictionary name and the value is the shared dictionary time recorder associated with + * that dictionary name. */ private static final ConcurrentHashMap<String, DictionaryUpdateController> - sFilenameDictionaryUpdateControllerMap = CollectionUtils.newConcurrentHashMap(); + sDictNameDictionaryUpdateControllerMap = CollectionUtils.newConcurrentHashMap(); private static final ConcurrentHashMap<String, PrioritizedSerialExecutor> - sFilenameExecutorMap = CollectionUtils.newConcurrentHashMap(); + sDictNameExecutorMap = CollectionUtils.newConcurrentHashMap(); /** The application context. */ protected final Context mContext; @@ -92,11 +92,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { protected AbstractDictionaryWriter mDictionaryWriter; /** - * The name of this dictionary, used as the filename for storing the binary dictionary. Multiple - * dictionary instances with the same filename is supported, with access controlled by - * DictionaryTimeRecorder. + * The name of this dictionary, used as a part of the filename for storing the binary + * dictionary. Multiple dictionary instances with the same name is supported, with access + * controlled by DictionaryUpdateController. */ - private final String mFilename; + private final String mDictName; /** Dictionary locale */ private final Locale mLocale; @@ -106,7 +106,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // TODO: remove, once dynamic operations is serialized /** Controls updating the shared binary dictionary file across multiple instances. */ - private final DictionaryUpdateController mFilenameDictionaryUpdateController; + private final DictionaryUpdateController mDictNameDictionaryUpdateController; // TODO: remove, once dynamic operations is serialized /** Controls updating the local binary dictionary for this instance. */ @@ -144,34 +144,46 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return mBinaryDictionary.isValidDictionary(); } - protected String getFileNameExtensionToOpenDict() { - return ""; + protected String getFileNameToCreateDict(final String dictName) { + return dictName + DICT_FILE_EXTENSION; + } + + protected String getFileNameToOpenDict(final String dictName) { + return getFileNameToCreateDict(dictName); + } + + private File getFileToCreateDict() { + return new File(mContext.getFilesDir(), getFileNameToCreateDict(mDictName)); + } + + private File getFileToOpenDict() { + return new File(mContext.getFilesDir(), getFileNameToOpenDict(mDictName)); } /** - * Gets the dictionary update controller for the given filename. + * Gets the dictionary update controller for the given dictionary name. */ private static DictionaryUpdateController getDictionaryUpdateController( - String filename) { - DictionaryUpdateController recorder = sFilenameDictionaryUpdateControllerMap.get(filename); + final String dictName) { + DictionaryUpdateController recorder = sDictNameDictionaryUpdateControllerMap.get(dictName); if (recorder == null) { - synchronized(sFilenameDictionaryUpdateControllerMap) { + synchronized(sDictNameDictionaryUpdateControllerMap) { recorder = new DictionaryUpdateController(); - sFilenameDictionaryUpdateControllerMap.put(filename, recorder); + sDictNameDictionaryUpdateControllerMap.put(dictName, recorder); } } return recorder; } /** - * Gets the executor for the given filename. + * Gets the executor for the given dictionary name. */ - private static PrioritizedSerialExecutor getExecutor(final String filename) { - PrioritizedSerialExecutor executor = sFilenameExecutorMap.get(filename); + private static PrioritizedSerialExecutor getExecutor(final String dictName) { + PrioritizedSerialExecutor executor = sDictNameExecutorMap.get(dictName); if (executor == null) { - synchronized(sFilenameExecutorMap) { + synchronized(sDictNameExecutorMap) { executor = new PrioritizedSerialExecutor(); - sFilenameExecutorMap.put(filename, executor); + sDictNameExecutorMap.put(dictName, executor); } } return executor; @@ -190,28 +202,28 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { * Creates a new expandable binary dictionary. * * @param context The application context of the parent. - * @param filename The filename for this binary dictionary. Multiple dictionaries with the same - * filename is supported. + * @param dictName The name of the dictionary. Multiple instances with the same + * name is supported. * @param locale the dictionary locale. * @param dictType the dictionary type, as a human-readable string * @param isUpdatable whether to support dynamically updating the dictionary. Please note that * dynamic dictionary has negative effects on memory space and computation time. */ - public ExpandableBinaryDictionary(final Context context, final String filename, + public ExpandableBinaryDictionary(final Context context, final String dictName, final Locale locale, final String dictType, final boolean isUpdatable) { super(dictType); - mFilename = filename; + mDictName = dictName; mContext = context; mLocale = locale; mIsUpdatable = isUpdatable; mBinaryDictionary = null; - mFilenameDictionaryUpdateController = getDictionaryUpdateController(filename); + mDictNameDictionaryUpdateController = getDictionaryUpdateController(dictName); // Currently, only dynamic personalization dictionary is updatable. mDictionaryWriter = getDictionaryWriter(context, isUpdatable); } - protected static String getFilenameWithLocale(final String name, final Locale locale) { - return name + "." + locale.toString() + DICT_FILE_EXTENSION; + protected static String getDictNameWithLocale(final String name, final Locale locale) { + return name + "." + locale.toString(); } /** @@ -219,7 +231,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ @Override public void close() { - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { if (mBinaryDictionary!= null) { @@ -232,7 +244,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { protected void closeBinaryDictionary() { // Ensure that no other threads are accessing the local binary dictionary. - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { if (mBinaryDictionary != null) { @@ -245,7 +257,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { protected Map<String, String> getHeaderAttributeMap() { HashMap<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.DICTIONARY_ID_ATTRIBUTE, mFilename); + attributeMap.put(FormatSpec.FileHeader.DICTIONARY_ID_ATTRIBUTE, mDictName); attributeMap.put(FormatSpec.FileHeader.DICTIONARY_LOCALE_ATTRIBUTE, mLocale.toString()); attributeMap.put(FormatSpec.FileHeader.DICTIONARY_VERSION_ATTRIBUTE, String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); @@ -253,19 +265,18 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } protected void clear() { - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { if (mDictionaryWriter == null) { mBinaryDictionary.close(); - final File file = new File(mContext.getFilesDir(), mFilename); + final File file = getFileToCreateDict(); file.delete(); BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), DICTIONARY_FORMAT_VERSION, getHeaderAttributeMap()); // We have 'fileToOpen' in addition to 'file' for the v4 dictionary format // where 'file' is a directory, and 'fileToOpen' is a normal file. - final File fileToOpen = new File(mContext.getFilesDir(), mFilename - + getFileNameExtensionToOpenDict()); + final File fileToOpen = getFileToOpenDict(); // TODO: Make BinaryDictionary's constructor be able to accept filename // without extension. mBinaryDictionary = new BinaryDictionary( @@ -305,7 +316,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { * Check whether GC is needed and run GC if required. */ protected void runGCIfRequired(final boolean mindsBlockByGC) { - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { runGCIfRequiredInternalLocked(mindsBlockByGC); @@ -318,13 +329,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { if (mBinaryDictionary.needsToRunGC(mindsBlockByGC)) { if (setProcessingLargeTaskIfNot()) { // Run GC after currently existing time sensitive operations. - getExecutor(mFilename).executePrioritized(new Runnable() { + getExecutor(mDictName).executePrioritized(new Runnable() { @Override public void run() { try { mBinaryDictionary.flushWithGC(); } finally { - mFilenameDictionaryUpdateController.mProcessingLargeTask.set(false); + mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false); } } }); @@ -339,10 +350,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord, final boolean isBlacklisted, final int timestamp) { if (!mIsUpdatable) { - Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mFilename); + Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mDictName); return; } - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { runGCIfRequiredInternalLocked(true /* mindsBlockByGC */); @@ -359,10 +370,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { final int frequency, final int timestamp) { if (!mIsUpdatable) { Log.w(TAG, "addBigramDynamically is called for non-updatable dictionary: " - + mFilename); + + mDictName); return; } - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { runGCIfRequiredInternalLocked(true /* mindsBlockByGC */); @@ -377,10 +388,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { protected void removeBigramDynamically(final String word0, final String word1) { if (!mIsUpdatable) { Log.w(TAG, "removeBigramDynamically is called for non-updatable dictionary: " - + mFilename); + + mDictName); return; } - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { runGCIfRequiredInternalLocked(true /* mindsBlockByGC */); @@ -401,10 +412,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { final AddMultipleDictionaryEntriesCallback callback) { if (!mIsUpdatable) { Log.w(TAG, "addMultipleDictionaryEntriesDynamically is called for non-updatable " + - "dictionary: " + mFilename); + "dictionary: " + mDictName); return; } - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { final boolean locked = setProcessingLargeTaskIfNot(); @@ -417,7 +428,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { callback.onFinished(); } if (locked) { - mFilenameDictionaryUpdateController.mProcessingLargeTask.set(false); + mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false); } } } @@ -435,7 +446,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } final AsyncResultHolder<ArrayList<SuggestedWordInfo>> holder = new AsyncResultHolder<ArrayList<SuggestedWordInfo>>(); - getExecutor(mFilename).executePrioritized(new Runnable() { + getExecutor(mDictName).executePrioritized(new Runnable() { @Override public void run() { if (mBinaryDictionary == null) { @@ -471,7 +482,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return false; } final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>(); - getExecutor(mFilename).executePrioritized(new Runnable() { + getExecutor(mDictName).executePrioritized(new Runnable() { @Override public void run() { holder.set(isValidWordLocked(word)); @@ -505,23 +516,22 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ private void loadBinaryDictionary() { if (DEBUG) { - Log.d(TAG, "Loading binary dictionary: " + mFilename + " request=" - + mFilenameDictionaryUpdateController.mLastUpdateRequestTime + " update=" - + mFilenameDictionaryUpdateController.mLastUpdateTime); + Log.d(TAG, "Loading binary dictionary: " + mDictName + " request=" + + mDictNameDictionaryUpdateController.mLastUpdateRequestTime + " update=" + + mDictNameDictionaryUpdateController.mLastUpdateTime); } if (DBG_STRESS_TEST) { // Test if this class does not cause problems when it takes long time to load binary // dictionary. try { - Log.w(TAG, "Start stress in loading: " + mFilename); + Log.w(TAG, "Start stress in loading: " + mDictName); Thread.sleep(15000); Log.w(TAG, "End stress in loading"); } catch (InterruptedException e) { } } - final File file = new File(mContext.getFilesDir(), mFilename - + getFileNameExtensionToOpenDict()); + final File file = getFileToOpenDict(); final String filename = file.getAbsolutePath(); final long length = file.length(); @@ -533,7 +543,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // swapping in the new one. // TODO: Ensure multi-thread assignment of mBinaryDictionary. final BinaryDictionary oldBinaryDictionary = mBinaryDictionary; - getExecutor(mFilename).executePrioritized(new Runnable() { + getExecutor(mDictName).executePrioritized(new Runnable() { @Override public void run() { mBinaryDictionary = newBinaryDictionary; @@ -555,20 +565,20 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ private void writeBinaryDictionary() { if (DEBUG) { - Log.d(TAG, "Generating binary dictionary: " + mFilename + " request=" - + mFilenameDictionaryUpdateController.mLastUpdateRequestTime + " update=" - + mFilenameDictionaryUpdateController.mLastUpdateTime); + Log.d(TAG, "Generating binary dictionary: " + mDictName + " request=" + + mDictNameDictionaryUpdateController.mLastUpdateRequestTime + " update=" + + mDictNameDictionaryUpdateController.mLastUpdateTime); } if (needsToReloadBeforeWriting()) { mDictionaryWriter.clear(); loadDictionaryAsync(); - mDictionaryWriter.write(mFilename, getHeaderAttributeMap()); + mDictionaryWriter.write(getFileNameToCreateDict(mDictName), getHeaderAttributeMap()); } else { if (mBinaryDictionary == null || !isValidDictionary() // TODO: remove the check below || !matchesExpectedBinaryDictFormatVersionForThisType( mBinaryDictionary.getFormatVersion())) { - final File file = new File(mContext.getFilesDir(), mFilename); + final File file = getFileToCreateDict(); if (!FileUtils.deleteRecursively(file)) { Log.e(TAG, "Can't remove a file: " + file.getName()); } @@ -594,10 +604,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { protected void setRequiresReload(final boolean requiresRebuild) { final long time = SystemClock.uptimeMillis(); mPerInstanceDictionaryUpdateController.mLastUpdateRequestTime = time; - mFilenameDictionaryUpdateController.mLastUpdateRequestTime = time; + mDictNameDictionaryUpdateController.mLastUpdateRequestTime = time; if (DEBUG) { - Log.d(TAG, "Reload request: " + mFilename + ": request=" + time + " update=" - + mFilenameDictionaryUpdateController.mLastUpdateTime); + Log.d(TAG, "Reload request: " + mDictName + ": request=" + time + " update=" + + mDictNameDictionaryUpdateController.mLastUpdateTime); } } @@ -619,13 +629,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } private boolean processingLargeTask() { - return mFilenameDictionaryUpdateController.mProcessingLargeTask.get(); + return mDictNameDictionaryUpdateController.mProcessingLargeTask.get(); } // Returns whether the dictionary is being used for a large task. If true, we should not use // this dictionary for latency sensitive operations. private boolean setProcessingLargeTaskIfNot() { - return mFilenameDictionaryUpdateController.mProcessingLargeTask.compareAndSet( + return mDictNameDictionaryUpdateController.mProcessingLargeTask.compareAndSet( false /* expect */ , true /* update */); } @@ -636,13 +646,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { private final void reloadDictionary() { // Ensure that only one thread attempts to read or write to the shared binary dictionary // file at the same time. - getExecutor(mFilename).execute(new Runnable() { + getExecutor(mDictName).execute(new Runnable() { @Override public void run() { try { final long time = SystemClock.uptimeMillis(); final boolean dictionaryFileExists = dictionaryFileExists(); - if (mFilenameDictionaryUpdateController.isOutOfDate() + if (mDictNameDictionaryUpdateController.isOutOfDate() || !dictionaryFileExists) { // If the shared dictionary file does not exist or is out of date, the // first instance that acquires the lock will generate a new one. @@ -651,18 +661,18 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // rebuild the binary dictionary. Empty dictionaries are supported (in // the case where loadDictionaryAsync() adds nothing) in order to // provide a uniform framework. - mFilenameDictionaryUpdateController.mLastUpdateTime = time; + mDictNameDictionaryUpdateController.mLastUpdateTime = time; writeBinaryDictionary(); loadBinaryDictionary(); } else { // If not, the reload request was unnecessary so revert // LastUpdateRequestTime to LastUpdateTime. - mFilenameDictionaryUpdateController.mLastUpdateRequestTime = - mFilenameDictionaryUpdateController.mLastUpdateTime; + mDictNameDictionaryUpdateController.mLastUpdateRequestTime = + mDictNameDictionaryUpdateController.mLastUpdateTime; } } else if (mBinaryDictionary == null || mPerInstanceDictionaryUpdateController.mLastUpdateTime - < mFilenameDictionaryUpdateController.mLastUpdateTime) { + < mDictNameDictionaryUpdateController.mLastUpdateTime) { // Otherwise, if the local dictionary is older than the shared dictionary, // load the shared dictionary. loadBinaryDictionary(); @@ -670,7 +680,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // If we just loaded the binary dictionary, then mBinaryDictionary is not // up-to-date yet so it's useless to test it right away. Schedule the check // for right after it's loaded instead. - getExecutor(mFilename).executePrioritized(new Runnable() { + getExecutor(mDictName).executePrioritized(new Runnable() { @Override public void run() { if (mBinaryDictionary != null && !(isValidDictionary() @@ -680,7 +690,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // Binary dictionary or its format version is not valid. Regenerate // the dictionary file. writeBinaryDictionary will remove the // existing files if appropriate. - mFilenameDictionaryUpdateController.mLastUpdateTime = time; + mDictNameDictionaryUpdateController.mLastUpdateTime = time; writeBinaryDictionary(); loadBinaryDictionary(); } @@ -688,7 +698,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } }); } finally { - mFilenameDictionaryUpdateController.mProcessingLargeTask.set(false); + mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false); } } }); @@ -696,7 +706,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // TODO: cache the file's existence so that we avoid doing a disk access each time. private boolean dictionaryFileExists() { - final File file = new File(mContext.getFilesDir(), mFilename); + final File file = getFileToOpenDict(); return file.exists(); } @@ -711,7 +721,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } }; final Runnable oldTask = mUnfinishedFlushingTask.getAndSet(newTask); - getExecutor(mFilename).replaceAndExecute(oldTask, newTask); + getExecutor(mDictName).replaceAndExecute(oldTask, newTask); } /** @@ -732,7 +742,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { @UsedForTesting public boolean isInDictionaryForTests(final String word) { final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>(); - getExecutor(mFilename).executePrioritized(new Runnable() { + getExecutor(mDictName).executePrioritized(new Runnable() { @Override public void run() { if (mDictType == Dictionary.TYPE_USER_HISTORY) { @@ -745,24 +755,24 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { @UsedForTesting public void shutdownExecutorForTests() { - getExecutor(mFilename).shutdown(); + getExecutor(mDictName).shutdown(); } @UsedForTesting public boolean isTerminatedForTests() { - return getExecutor(mFilename).isTerminated(); + return getExecutor(mDictName).isTerminated(); } @UsedForTesting protected void runAfterGcForDebug(final Runnable r) { - getExecutor(mFilename).executePrioritized(new Runnable() { + getExecutor(mDictName).executePrioritized(new Runnable() { @Override public void run() { try { mBinaryDictionary.flushWithGC(); r.run(); } finally { - mFilenameDictionaryUpdateController.mProcessingLargeTask.set(false); + mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false); } } }); diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index cc7687b62..1dc3c54bb 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -18,7 +18,6 @@ package com.android.inputmethod.latin; import android.content.ContentProviderClient; import android.content.ContentResolver; -import android.content.ContentUris; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; @@ -81,7 +80,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { public UserBinaryDictionary(final Context context, final Locale locale, final boolean alsoUseMoreRestrictiveLocales) { - super(context, getFilenameWithLocale(NAME, locale), locale, Dictionary.TYPE_USER, + super(context, getDictNameWithLocale(NAME, locale), locale, Dictionary.TYPE_USER, false /* isUpdatable */); if (null == locale) throw new NullPointerException(); // Catch the error earlier final String localeStr = locale.toString(); diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java index 386e1232f..8321df94b 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java +++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java @@ -58,13 +58,13 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB /** Locale for which this user history dictionary is storing words */ private final Locale mLocale; - private final String mFileName; + private final String mDictName; /* package */ DecayingExpandableBinaryDictionaryBase(final Context context, - final Locale locale, final String dictionaryType, final String fileName) { - super(context, fileName, locale, dictionaryType, true); + final Locale locale, final String dictionaryType, final String dictName) { + super(context, dictName, locale, dictionaryType, true); mLocale = locale; - mFileName = fileName; + mDictName = dictName; if (mLocale != null && mLocale.toString().length() > 1) { reloadDictionaryIfRequired(); } @@ -88,7 +88,7 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(FormatSpec.FileHeader.HAS_HISTORICAL_INFO_ATTRIBUTE, FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - attributeMap.put(FormatSpec.FileHeader.DICTIONARY_ID_ATTRIBUTE, mFileName); + attributeMap.put(FormatSpec.FileHeader.DICTIONARY_ID_ATTRIBUTE, mDictName); attributeMap.put(FormatSpec.FileHeader.DICTIONARY_LOCALE_ATTRIBUTE, mLocale.toString()); attributeMap.put(FormatSpec.FileHeader.DICTIONARY_VERSION_ATTRIBUTE, String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); @@ -113,9 +113,13 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB } @Override - protected String getFileNameExtensionToOpenDict() { - // TODO: pass the directory name instead - return "/" + FormatSpec.HEADER_FILE_EXTENSION; + protected String getFileNameToCreateDict(final String dictName) { + return dictName; + } + + @Override + protected String getFileNameToOpenDict(final String dictName) { + return dictName + "/" + dictName + FormatSpec.HEADER_FILE_EXTENSION; } public void addMultipleDictionaryEntriesToDictionary( @@ -194,7 +198,7 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB }; // Load the dictionary from binary file - final File dictFile = new File(mContext.getFilesDir(), mFileName); + final File dictFile = new File(mContext.getFilesDir(), mDictName); final DictDecoder dictDecoder = FormatSpec.getDictDecoder(dictFile, DictDecoder.USE_BYTEARRAY); if (dictDecoder == null) { diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java index 413a951ad..b1ec76f28 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java @@ -17,7 +17,6 @@ package com.android.inputmethod.latin.personalization; import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.ExpandableBinaryDictionary; import com.android.inputmethod.latin.utils.CollectionUtils; import java.util.ArrayList; @@ -33,11 +32,7 @@ public class PersonalizationDictionary extends DecayingExpandableBinaryDictionar /* package */ PersonalizationDictionary(final Context context, final Locale locale) { super(context, locale, Dictionary.TYPE_PERSONALIZATION, - getDictionaryFileName(locale.toString())); - } - - private static String getDictionaryFileName(final String locale) { - return NAME + "." + locale + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + getDictNameWithLocale(NAME, locale)); } public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) { diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java index 975224f7c..3f03de0d4 100644 --- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java @@ -17,7 +17,6 @@ package com.android.inputmethod.latin.personalization; import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.ExpandableBinaryDictionary; import java.util.Locale; @@ -31,12 +30,7 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas /* package for tests */ static final String NAME = UserHistoryDictionary.class.getSimpleName(); /* package */ UserHistoryDictionary(final Context context, final Locale locale) { - super(context, locale, Dictionary.TYPE_USER_HISTORY, - getDictionaryFileName(locale.toString())); - } - - private static String getDictionaryFileName(final String locale) { - return NAME + "." + locale + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + super(context, locale, Dictionary.TYPE_USER_HISTORY, getDictNameWithLocale(NAME, locale)); } public void cancelAddingUserHistory(final String word0, final String word1) { diff --git a/java/src/com/android/inputmethod/latin/utils/JsonUtils.java b/java/src/com/android/inputmethod/latin/utils/JsonUtils.java new file mode 100644 index 000000000..764ef72ce --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/JsonUtils.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package com.android.inputmethod.latin.utils; + +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import java.io.Closeable; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class JsonUtils { + private static final String TAG = JsonUtils.class.getSimpleName(); + + private static final String INTEGER_CLASS_NAME = Integer.class.getSimpleName(); + private static final String STRING_CLASS_NAME = String.class.getSimpleName(); + + private static final String EMPTY_STRING = ""; + + public static List<Object> jsonStrToList(final String s) { + final ArrayList<Object> list = CollectionUtils.newArrayList(); + final JsonReader reader = new JsonReader(new StringReader(s)); + try { + reader.beginArray(); + while (reader.hasNext()) { + reader.beginObject(); + while (reader.hasNext()) { + final String name = reader.nextName(); + if (name.equals(INTEGER_CLASS_NAME)) { + list.add(reader.nextInt()); + } else if (name.equals(STRING_CLASS_NAME)) { + list.add(reader.nextString()); + } else { + Log.w(TAG, "Invalid name: " + name); + reader.skipValue(); + } + } + reader.endObject(); + } + reader.endArray(); + return list; + } catch (final IOException e) { + } finally { + close(reader); + } + return Collections.<Object>emptyList(); + } + + public static String listToJsonStr(final List<Object> list) { + if (list == null || list.isEmpty()) { + return EMPTY_STRING; + } + final StringWriter sw = new StringWriter(); + final JsonWriter writer = new JsonWriter(sw); + try { + writer.beginArray(); + for (final Object o : list) { + writer.beginObject(); + if (o instanceof Integer) { + writer.name(INTEGER_CLASS_NAME).value((Integer)o); + } else if (o instanceof String) { + writer.name(STRING_CLASS_NAME).value((String)o); + } + writer.endObject(); + } + writer.endArray(); + return sw.toString(); + } catch (final IOException e) { + } finally { + close(writer); + } + return EMPTY_STRING; + } + + private static void close(final Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (final IOException e) { + // Ignore + } + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java index 928000ec9..df420417d 100644 --- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java @@ -17,20 +17,14 @@ package com.android.inputmethod.latin.utils; import android.text.TextUtils; -import android.util.JsonReader; -import android.util.JsonWriter; import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.settings.SettingsValues; -import java.io.Closeable; import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Locale; @@ -426,72 +420,4 @@ public final class StringUtils { } return bytes; } - - private static final String INTEGER_CLASS_NAME = Integer.class.getSimpleName(); - private static final String STRING_CLASS_NAME = String.class.getSimpleName(); - - public static List<Object> jsonStrToList(final String s) { - final ArrayList<Object> list = CollectionUtils.newArrayList(); - final JsonReader reader = new JsonReader(new StringReader(s)); - try { - reader.beginArray(); - while (reader.hasNext()) { - reader.beginObject(); - while (reader.hasNext()) { - final String name = reader.nextName(); - if (name.equals(INTEGER_CLASS_NAME)) { - list.add(reader.nextInt()); - } else if (name.equals(STRING_CLASS_NAME)) { - list.add(reader.nextString()); - } else { - Log.w(TAG, "Invalid name: " + name); - reader.skipValue(); - } - } - reader.endObject(); - } - reader.endArray(); - return list; - } catch (final IOException e) { - } finally { - close(reader); - } - return Collections.<Object>emptyList(); - } - - public static String listToJsonStr(final List<Object> list) { - if (list == null || list.isEmpty()) { - return EMPTY_STRING; - } - final StringWriter sw = new StringWriter(); - final JsonWriter writer = new JsonWriter(sw); - try { - writer.beginArray(); - for (final Object o : list) { - writer.beginObject(); - if (o instanceof Integer) { - writer.name(INTEGER_CLASS_NAME).value((Integer)o); - } else if (o instanceof String) { - writer.name(STRING_CLASS_NAME).value((String)o); - } - writer.endObject(); - } - writer.endArray(); - return sw.toString(); - } catch (final IOException e) { - } finally { - close(writer); - } - return EMPTY_STRING; - } - - private static void close(final Closeable closeable) { - try { - if (closeable != null) { - closeable.close(); - } - } catch (final IOException e) { - // Ignore - } - } } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h index ac05b215b..95ee74f99 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h @@ -73,8 +73,8 @@ class BigramDictContent : public SparseTableDictContent { bool copyBigramList(const int bigramListPos, const int toPos); - bool flushToFile(const char *const dictDirPath) const { - return flush(dictDirPath, Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION, + bool flushToFile(const char *const dictBasePath) const { + return flush(dictBasePath, Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION, Ver4DictConstants::BIGRAM_CONTENT_TABLE_FILE_EXTENSION, Ver4DictConstants::BIGRAM_FILE_EXTENSION); } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp index 01e406b74..749e3fe8c 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp @@ -71,7 +71,7 @@ bool ProbabilityDictContent::setProbabilityEntry(const int terminalId, return writeEntry(probabilityEntry, entryPos); } -bool ProbabilityDictContent::flushToFile(const char *const dictDirPath) const { +bool ProbabilityDictContent::flushToFile(const char *const dictBasePath) const { if (getEntryPos(mSize) < getBuffer()->getTailPosition()) { ProbabilityDictContent probabilityDictContentToWrite(mHasHistoricalInfo); for (int i = 0; i < mSize; ++i) { @@ -81,10 +81,10 @@ bool ProbabilityDictContent::flushToFile(const char *const dictDirPath) const { return false; } } - return probabilityDictContentToWrite.flush(dictDirPath, + return probabilityDictContentToWrite.flush(dictBasePath, Ver4DictConstants::FREQ_FILE_EXTENSION); } else { - return flush(dictDirPath, Ver4DictConstants::FREQ_FILE_EXTENSION); + return flush(dictBasePath, Ver4DictConstants::FREQ_FILE_EXTENSION); } } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp index eca69ec23..555217837 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp @@ -46,8 +46,8 @@ int ShortcutDictContent::getShortcutListHeadPos(const int terminalId) const { return addressLookupTable->get(terminalId); } -bool ShortcutDictContent::flushToFile(const char *const dictDirPath) const { - return flush(dictDirPath, Ver4DictConstants::SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION, +bool ShortcutDictContent::flushToFile(const char *const dictBasePath) const { + return flush(dictBasePath, Ver4DictConstants::SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION, Ver4DictConstants::SHORTCUT_CONTENT_TABLE_FILE_EXTENSION, Ver4DictConstants::SHORTCUT_FILE_EXTENSION); } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h index 670e6eab6..a52214ca2 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h @@ -53,7 +53,7 @@ class ShortcutDictContent : public SparseTableDictContent { // Returns head position of shortcut list for a PtNode specified by terminalId. int getShortcutListHeadPos(const int terminalId) const; - bool flushToFile(const char *const dictDirPath) const; + bool flushToFile(const char *const dictBasePath) const; bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, const ShortcutDictContent *const originalShortcutDictContent); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h index 9512bdbb0..d8eedf36e 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h @@ -59,9 +59,9 @@ class SingleDictContent : public DictContent { return &mExpandableContentBuffer; } - bool flush(const char *const dictDirPath, const char *const contentFileName) const { - return DictFileWritingUtils::flushBufferToFileInDir(dictDirPath, contentFileName, - &mExpandableContentBuffer); + bool flush(const char *const dictBasePath, const char *const contentFileNameSuffix) const { + return DictFileWritingUtils::flushBufferToFileWithSuffix(dictBasePath, + contentFileNameSuffix, &mExpandableContentBuffer); } private: diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp index 84aceeffe..abb7d5fd2 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp @@ -18,18 +18,18 @@ namespace latinime { -bool SparseTableDictContent::flush(const char *const dictDirPath, - const char *const lookupTableFileName, const char *const addressTableFileName, - const char *const contentFileName) const { - if (!DictFileWritingUtils::flushBufferToFileInDir(dictDirPath, lookupTableFileName, +bool SparseTableDictContent::flush(const char *const dictBasePath, + const char *const lookupTableFileNameSuffix, const char *const addressTableFileNameSuffix, + const char *const contentFileNameSuffix) const { + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictBasePath, lookupTableFileNameSuffix, &mExpandableLookupTableBuffer)){ return false; } - if (!DictFileWritingUtils::flushBufferToFileInDir(dictDirPath, addressTableFileName, + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictBasePath, addressTableFileNameSuffix, &mExpandableAddressTableBuffer)) { return false; } - if (!DictFileWritingUtils::flushBufferToFileInDir(dictDirPath, contentFileName, + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictBasePath, contentFileNameSuffix, &mExpandableContentBuffer)) { return false; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp index 24f62cd4b..c889cf5d1 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp @@ -50,7 +50,7 @@ bool TerminalPositionLookupTable::setTerminalPtNodePosition( Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(terminalId)); } -bool TerminalPositionLookupTable::flushToFile(const char *const dictDirPath) const { +bool TerminalPositionLookupTable::flushToFile(const char *const dictBasePath) const { // If the used buffer size is smaller than the actual buffer size, regenerate the lookup // table and write the new table to the file. if (getEntryPos(mSize) < getBuffer()->getTailPosition()) { @@ -63,12 +63,12 @@ bool TerminalPositionLookupTable::flushToFile(const char *const dictDirPath) con return false; } } - return lookupTableToWrite.flush(dictDirPath, + return lookupTableToWrite.flush(dictBasePath, Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); } else { // We can simply use this lookup table because the buffer size has not been // changed. - return flush(dictDirPath, Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); + return flush(dictBasePath, Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); } } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h index 283b40237..5a28f52fd 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h @@ -44,7 +44,7 @@ class TerminalPositionLookupTable : public SingleDictContent { return mSize; } - bool flushToFile(const char *const dictDirPath) const; + bool flushToFile(const char *const dictBasePath) const; bool runGCTerminalIds(TerminalIdMap *const terminalIdMap); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp index d17d2d597..e2355407a 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp @@ -17,6 +17,7 @@ #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" #include <cerrno> +#include <cstring> #include <sys/stat.h> #include <sys/types.h> @@ -52,34 +53,42 @@ bool Ver4DictBuffers::flushHeaderAndDictBuffers(const char *const dictDirPath, AKLOGE("Cannot create directory: %s. errno: %d.", tmpDirPath, errno); return false; } + // Get dictionary base path. + const int dictNameBufSize = strlen(dictDirPath) + 1 /* terminator */; + char dictName[dictNameBufSize]; + FileUtils::getBasename(dictDirPath, dictNameBufSize, dictName); + const int dictBasePathBufSize = FileUtils::getFilePathBufSize(tmpDirPath, dictName); + char dictBasePath[dictBasePathBufSize]; + FileUtils::getFilePath(tmpDirPath, dictName, dictBasePathBufSize, dictBasePath); + // Write header file. - if (!DictFileWritingUtils::flushBufferToFileInDir(tmpDirPath, + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictBasePath, Ver4DictConstants::HEADER_FILE_EXTENSION, headerBuffer)) { - AKLOGE("Dictionary header file %s/%s cannot be written.", tmpDirPath, + AKLOGE("Dictionary header file %s%s cannot be written.", tmpDirPath, Ver4DictConstants::HEADER_FILE_EXTENSION); return false; } // Write trie file. - if (!DictFileWritingUtils::flushBufferToFileInDir(tmpDirPath, + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictBasePath, Ver4DictConstants::TRIE_FILE_EXTENSION, &mExpandableTrieBuffer)) { - AKLOGE("Dictionary trie file %s/%s cannot be written.", tmpDirPath, + AKLOGE("Dictionary trie file %s%s cannot be written.", tmpDirPath, Ver4DictConstants::TRIE_FILE_EXTENSION); return false; } // Write dictionary contents. - if (!mTerminalPositionLookupTable.flushToFile(tmpDirPath)) { + if (!mTerminalPositionLookupTable.flushToFile(dictBasePath)) { AKLOGE("Terminal position lookup table cannot be written. %s", tmpDirPath); return false; } - if (!mProbabilityDictContent.flushToFile(tmpDirPath)) { + if (!mProbabilityDictContent.flushToFile(dictBasePath)) { AKLOGE("Probability dict content cannot be written. %s", tmpDirPath); return false; } - if (!mBigramDictContent.flushToFile(tmpDirPath)) { + if (!mBigramDictContent.flushToFile(dictBasePath)) { AKLOGE("Bigram dict content cannot be written. %s", tmpDirPath); return false; } - if (!mShortcutDictContent.flushToFile(tmpDirPath)) { + if (!mShortcutDictContent.flushToFile(dictBasePath)) { AKLOGE("Shortcut dict content cannot be written. %s", tmpDirPath); return false; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp index ec67c188f..442373b29 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp @@ -83,11 +83,11 @@ const char *const DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE = return true; } -/* static */ bool DictFileWritingUtils::flushBufferToFileInDir(const char *const dirPath, - const char *const fileName, const BufferWithExtendableBuffer *const buffer) { - const int filePathBufSize = FileUtils::getFilePathBufSize(dirPath, fileName); +/* static */ bool DictFileWritingUtils::flushBufferToFileWithSuffix(const char *const basePath, + const char *const suffix, const BufferWithExtendableBuffer *const buffer) { + const int filePathBufSize = FileUtils::getFilePathWithSuffixBufSize(basePath, suffix); char filePath[filePathBufSize]; - FileUtils::getFilePath(dirPath, fileName, filePathBufSize, filePath); + FileUtils::getFilePathWithSuffix(basePath, suffix, filePathBufSize, filePath); return flushBufferToFile(filePath, buffer); } diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h index ffd9db623..bdf9fd63c 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h @@ -37,7 +37,7 @@ class DictFileWritingUtils { BufferWithExtendableBuffer *const dictHeader, BufferWithExtendableBuffer *const dictBody); - static bool flushBufferToFileInDir(const char *const dirPath, const char *const fileName, + static bool flushBufferToFileWithSuffix(const char *const basePath, const char *const suffix, const BufferWithExtendableBuffer *const buffer); private: diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp index 34da76903..49ae7f156 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp @@ -20,6 +20,7 @@ #include <cstring> #include <dirent.h> #include <fcntl.h> +#include <libgen.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> @@ -138,4 +139,19 @@ namespace latinime { } } +/* static */ void FileUtils::getBasename(const char *const filePath, + const int outNameBufSize, char *const outName) { + const int filePathBufSize = strlen(filePath) + 1 /* terminator */; + char filePathBuf[filePathBufSize]; + snprintf(filePathBuf, filePathBufSize, "%s", filePath); + const char *const baseName = basename(filePathBuf); + const int baseNameLength = strlen(baseName); + if (baseNameLength >= outNameBufSize) { + AKLOGE("outNameBufSize is too small. dirPath: %s, outNameBufSize: %d", + filePath, outNameBufSize); + return; + } + snprintf(outName, baseNameLength + 1 /* terminator */, "%s", baseName); +} + } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h index e55837337..3e84a3038 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h @@ -48,6 +48,9 @@ class FileUtils { static void getDirPath(const char *const filePath, const int dirPathBufSize, char *const outDirPath); + static void getBasename(const char *const filePath, const int outNameBufSize, + char *const outName); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtils); }; diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java index d76a55283..931ba7d3c 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java @@ -122,12 +122,13 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(FormatSpec.FileHeader.HAS_HISTORICAL_INFO_ATTRIBUTE, FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); + final String headerFileName = file.getName() + FormatSpec.HEADER_FILE_EXTENSION; if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, attributeMap)) { - return new File(file, FormatSpec.HEADER_FILE_EXTENSION); + return new File(file, headerFileName); } else { throw new IOException("Empty dictionary " + file.getAbsolutePath() + " " - + FormatSpec.HEADER_FILE_EXTENSION + " cannot be created."); + + headerFileName + " cannot be created."); } } diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java index c14840258..d9d4a5584 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java @@ -70,12 +70,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { Map<String, String> attributeMap = new HashMap<String, String>(); attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); + final String headerFileName = file.getName() + FormatSpec.HEADER_FILE_EXTENSION; if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, attributeMap)) { - return new File(file, FormatSpec.HEADER_FILE_EXTENSION); + return new File(file, headerFileName); } else { throw new IOException("Empty dictionary " + file.getAbsolutePath() + " " - + FormatSpec.HEADER_FILE_EXTENSION + " cannot be created."); + + headerFileName + " cannot be created."); } } diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java index 717b04f75..f0fe3f2e1 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java @@ -20,7 +20,6 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; -import com.android.inputmethod.latin.ExpandableBinaryDictionary; import com.android.inputmethod.latin.utils.CollectionUtils; import java.io.File; @@ -137,8 +136,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { Log.d(TAG, "This test can be used for profiling."); Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true."); final String testFilenameSuffix = "test_random_words" + System.currentTimeMillis(); - final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix - + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix; final int numberOfWords = 1000; final Random random = new Random(123456); @@ -172,8 +170,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { // Create filename suffixes for this test. for (int i = 0; i < numberOfLanguages; i++) { testFilenameSuffixes[i] = "test_switching_languages" + i; - final String fileName = UserHistoryDictionary.NAME + "." + - testFilenameSuffixes[i] + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffixes[i]; dictFiles[i] = new File(getContext().getFilesDir(), fileName); clearHistory(testFilenameSuffixes[i]); } @@ -217,8 +214,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { } finally { Log.d(TAG, "waiting for writing ..."); waitForWriting(testFilenameSuffix); - final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix - + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix; final File dictFile = new File(getContext().getFilesDir(), fileName); if (dictFile != null) { assertTrue(dictFile.exists()); diff --git a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java index 21fcf1117..2123e84e8 100644 --- a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.Locale; @SmallTest -public class StringUtilsTests extends AndroidTestCase { +public class StringAndJsonUtilsTests extends AndroidTestCase { public void testContainsInArray() { assertFalse("empty array", StringUtils.containsInArray("key", new String[0])); assertFalse("not in 1 element", StringUtils.containsInArray("key", new String[] { @@ -292,11 +292,11 @@ public class StringUtilsTests extends AndroidTestCase { assertTrue(bytesStr.equals(bytesStr2)); } - public void testJsonStringUtils() { + public void testJsonUtils() { final Object[] objs = new Object[] { 1, "aaa", "bbb", 3 }; final List<Object> objArray = Arrays.asList(objs); - final String str = StringUtils.listToJsonStr(objArray); - final List<Object> newObjArray = StringUtils.jsonStrToList(str); + final String str = JsonUtils.listToJsonStr(objArray); + final List<Object> newObjArray = JsonUtils.jsonStrToList(str); for (int i = 0; i < objs.length; ++i) { assertEquals(objs[i], newObjArray.get(i)); } diff --git a/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml index deae87939..f4fe7f787 100644 --- a/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml @@ -67,8 +67,6 @@ U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> <string name="more_keys_for_c">ç,ć,č</string> - <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> - <string name="keylabel_for_spanish_row2_10">ñ</string> <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK U+00BF: "¿" INVERTED QUESTION MARK --> <string name="more_keys_for_punctuation">"!fixedColumnOrder!9,¡,;,/,(,),#,!,\\,,\?,¿,&,\\%,+,\",-,:,',\@"</string> diff --git a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml index c1f3e4cea..ceb46dcd2 100644 --- a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml @@ -189,7 +189,8 @@ <string name="keylabel_for_w">w</string> <string name="keylabel_for_y">y</string> <string name="keylabel_for_x">x</string> - <string name="keylabel_for_spanish_row2_10"></string> + <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> + <string name="keylabel_for_spanish_row2_10">ñ</string> <string name="more_keys_for_am_pm">!fixedColumnOrder!2,!hasLabels!,\@string/label_time_am,\@string/label_time_pm</string> <string name="settings_as_more_key">!icon/settings_key|!code/key_settings</string> <string name="shortcut_as_more_key">!icon/shortcut_key|!code/key_shortcut</string> |