Loading java/src/com/android/inputmethod/latin/BinaryDictionary.java +22 −1 Original line number Diff line number Diff line Loading @@ -28,9 +28,10 @@ import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.personalization.PersonalizationHelper; import com.android.inputmethod.latin.settings.NativeSuggestOptions; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; 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; Loading Loading @@ -81,6 +82,8 @@ public final class BinaryDictionary extends Dictionary { public static final int FORMAT_WORD_PROPERTY_LEVEL_INDEX = 2; public static final int FORMAT_WORD_PROPERTY_COUNT_INDEX = 3; public static final String DICT_FILE_NAME_SUFFIX_FOR_MIGRATION = ".migrate"; private long mNativeDict; private final Locale mLocale; private final long mDictSize; Loading Loading @@ -458,6 +461,24 @@ public final class BinaryDictionary extends Dictionary { return needsToRunGCNative(mNativeDict, mindsBlockByGC); } public boolean migrateTo(final int newFormatVersion) { if (!isValidDictionary()) { return false; } final String tmpDictFilePath = mDictFilePath + DICT_FILE_NAME_SUFFIX_FOR_MIGRATION; // TODO: Implement migrateNative(tmpDictFilePath, newFormatVersion). close(); final File dictFile = new File(mDictFilePath); final File tmpDictFile = new File(tmpDictFilePath); FileUtils.deleteRecursively(dictFile); if (!BinaryDictionaryUtils.renameDict(tmpDictFile, dictFile)) { return false; } loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */, dictFile.length(), mIsUpdatable); return true; } @UsedForTesting public int calculateProbability(final int unigramProbability, final int bigramProbability) { if (!isValidDictionary()) return NOT_A_PROBABILITY; Loading java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +9 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return formatVersion == FormatSpec.VERSION4; } private boolean needsToMigrateDictionary(final int formatVersion) { // TODO: Check version. return false; } public boolean isValidDictionaryLocked() { return mBinaryDictionary.isValidDictionary(); } Loading Loading @@ -477,6 +482,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { if (oldBinaryDictionary != null) { oldBinaryDictionary.close(); } if (mBinaryDictionary.isValidDictionary() && needsToMigrateDictionary(mBinaryDictionary.getFormatVersion())) { mBinaryDictionary.migrateTo(DICTIONARY_FORMAT_VERSION); } } /** Loading java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java +27 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import java.io.File; import java.io.IOException; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public final class BinaryDictionaryUtils { private static final String TAG = BinaryDictionaryUtils.class.getSimpleName(); Loading Loading @@ -64,6 +66,31 @@ public final class BinaryDictionaryUtils { return header; } public static boolean renameDict(final File dictFile, final File newDictFile) { if (dictFile.isFile()) { return dictFile.renameTo(newDictFile); } else if (dictFile.isDirectory()) { final String dictName = dictFile.getName(); final String newDictName = newDictFile.getName(); if (newDictFile.exists()) { return false; } for (final File file : dictFile.listFiles()) { if (!file.isFile()) { continue; } final String fileName = file.getName(); final String newFileName = fileName.replaceFirst( Pattern.quote(dictName), Matcher.quoteReplacement(newDictName)); if (!file.renameTo(new File(dictFile, newFileName))) { return false; } } return dictFile.renameTo(newDictFile); } return false; } public static boolean createEmptyDictFile(final String filePath, final long dictVersion, final Locale locale, final Map<String, String> attributeMap) { final String[] keyArray = new String[attributeMap.size()]; Loading tests/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtilsTests.java 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * 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.utils; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; @LargeTest public class BinaryDictionaryUtilsTests extends AndroidTestCase { private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; private static final String TEST_LOCALE = "test"; private File createEmptyDictionaryAndGetFile(final String dictId, final int formatVersion) throws IOException { if (formatVersion == FormatSpec.VERSION4) { return createEmptyVer4DictionaryAndGetFile(dictId); } else { throw new IOException("Dictionary format version " + formatVersion + " is not supported."); } } private File createEmptyVer4DictionaryAndGetFile(final String dictId) throws IOException { final File file = getDictFile(dictId); FileUtils.deleteRecursively(file); Map<String, String> attributeMap = new HashMap<String, String>(); attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, dictId); attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY, String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, DictionaryHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, DictionaryHeader.ATTRIBUTE_VALUE_TRUE); if (BinaryDictionaryUtils.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, LocaleUtils.constructLocaleFromString(TEST_LOCALE), attributeMap)) { return file; } else { throw new IOException("Empty dictionary " + file.getAbsolutePath() + " cannot be created."); } } private File getDictFile(final String dictId) { return new File(getContext().getCacheDir(), dictId + TEST_DICT_FILE_EXTENSION); } public void testRenameDictionary() { final int formatVersion = FormatSpec.VERSION4; File dictFile0 = null; try { dictFile0 = createEmptyDictionaryAndGetFile("MoveFromDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } final File dictFile1 = getDictFile("MoveToDictionary"); FileUtils.deleteRecursively(dictFile1); assertTrue(BinaryDictionaryUtils.renameDict(dictFile0, dictFile1)); assertFalse(dictFile0.exists()); assertTrue(dictFile1.exists()); BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile1.getAbsolutePath(), 0 /* offset */, dictFile1.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); assertTrue(binaryDictionary.isValidDictionary()); assertTrue(binaryDictionary.getFormatVersion() == formatVersion); binaryDictionary.close(); } } Loading
java/src/com/android/inputmethod/latin/BinaryDictionary.java +22 −1 Original line number Diff line number Diff line Loading @@ -28,9 +28,10 @@ import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.personalization.PersonalizationHelper; import com.android.inputmethod.latin.settings.NativeSuggestOptions; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; 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; Loading Loading @@ -81,6 +82,8 @@ public final class BinaryDictionary extends Dictionary { public static final int FORMAT_WORD_PROPERTY_LEVEL_INDEX = 2; public static final int FORMAT_WORD_PROPERTY_COUNT_INDEX = 3; public static final String DICT_FILE_NAME_SUFFIX_FOR_MIGRATION = ".migrate"; private long mNativeDict; private final Locale mLocale; private final long mDictSize; Loading Loading @@ -458,6 +461,24 @@ public final class BinaryDictionary extends Dictionary { return needsToRunGCNative(mNativeDict, mindsBlockByGC); } public boolean migrateTo(final int newFormatVersion) { if (!isValidDictionary()) { return false; } final String tmpDictFilePath = mDictFilePath + DICT_FILE_NAME_SUFFIX_FOR_MIGRATION; // TODO: Implement migrateNative(tmpDictFilePath, newFormatVersion). close(); final File dictFile = new File(mDictFilePath); final File tmpDictFile = new File(tmpDictFilePath); FileUtils.deleteRecursively(dictFile); if (!BinaryDictionaryUtils.renameDict(tmpDictFile, dictFile)) { return false; } loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */, dictFile.length(), mIsUpdatable); return true; } @UsedForTesting public int calculateProbability(final int unigramProbability, final int bigramProbability) { if (!isValidDictionary()) return NOT_A_PROBABILITY; Loading
java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +9 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return formatVersion == FormatSpec.VERSION4; } private boolean needsToMigrateDictionary(final int formatVersion) { // TODO: Check version. return false; } public boolean isValidDictionaryLocked() { return mBinaryDictionary.isValidDictionary(); } Loading Loading @@ -477,6 +482,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { if (oldBinaryDictionary != null) { oldBinaryDictionary.close(); } if (mBinaryDictionary.isValidDictionary() && needsToMigrateDictionary(mBinaryDictionary.getFormatVersion())) { mBinaryDictionary.migrateTo(DICTIONARY_FORMAT_VERSION); } } /** Loading
java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java +27 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import java.io.File; import java.io.IOException; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public final class BinaryDictionaryUtils { private static final String TAG = BinaryDictionaryUtils.class.getSimpleName(); Loading Loading @@ -64,6 +66,31 @@ public final class BinaryDictionaryUtils { return header; } public static boolean renameDict(final File dictFile, final File newDictFile) { if (dictFile.isFile()) { return dictFile.renameTo(newDictFile); } else if (dictFile.isDirectory()) { final String dictName = dictFile.getName(); final String newDictName = newDictFile.getName(); if (newDictFile.exists()) { return false; } for (final File file : dictFile.listFiles()) { if (!file.isFile()) { continue; } final String fileName = file.getName(); final String newFileName = fileName.replaceFirst( Pattern.quote(dictName), Matcher.quoteReplacement(newDictName)); if (!file.renameTo(new File(dictFile, newFileName))) { return false; } } return dictFile.renameTo(newDictFile); } return false; } public static boolean createEmptyDictFile(final String filePath, final long dictVersion, final Locale locale, final Map<String, String> attributeMap) { final String[] keyArray = new String[attributeMap.size()]; Loading
tests/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtilsTests.java 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * 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.utils; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; @LargeTest public class BinaryDictionaryUtilsTests extends AndroidTestCase { private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; private static final String TEST_LOCALE = "test"; private File createEmptyDictionaryAndGetFile(final String dictId, final int formatVersion) throws IOException { if (formatVersion == FormatSpec.VERSION4) { return createEmptyVer4DictionaryAndGetFile(dictId); } else { throw new IOException("Dictionary format version " + formatVersion + " is not supported."); } } private File createEmptyVer4DictionaryAndGetFile(final String dictId) throws IOException { final File file = getDictFile(dictId); FileUtils.deleteRecursively(file); Map<String, String> attributeMap = new HashMap<String, String>(); attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, dictId); attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY, String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, DictionaryHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, DictionaryHeader.ATTRIBUTE_VALUE_TRUE); if (BinaryDictionaryUtils.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, LocaleUtils.constructLocaleFromString(TEST_LOCALE), attributeMap)) { return file; } else { throw new IOException("Empty dictionary " + file.getAbsolutePath() + " cannot be created."); } } private File getDictFile(final String dictId) { return new File(getContext().getCacheDir(), dictId + TEST_DICT_FILE_EXTENSION); } public void testRenameDictionary() { final int formatVersion = FormatSpec.VERSION4; File dictFile0 = null; try { dictFile0 = createEmptyDictionaryAndGetFile("MoveFromDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } final File dictFile1 = getDictFile("MoveToDictionary"); FileUtils.deleteRecursively(dictFile1); assertTrue(BinaryDictionaryUtils.renameDict(dictFile0, dictFile1)); assertFalse(dictFile0.exists()); assertTrue(dictFile1.exists()); BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile1.getAbsolutePath(), 0 /* offset */, dictFile1.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); assertTrue(binaryDictionary.isValidDictionary()); assertTrue(binaryDictionary.getFormatVersion() == formatVersion); binaryDictionary.close(); } }