Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a785fa8e authored by Keisuke Kuroyanagi's avatar Keisuke Kuroyanagi
Browse files

Dictionary migration in Java side.

Bug: 13406708

Change-Id: If83938e4b4810d2e8353c70cdd8ef3ea97a29571
parent 3c38e1f2
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
+9 −0
Original line number Diff line number Diff line
@@ -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();
    }
@@ -471,6 +476,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
        if (oldBinaryDictionary != null) {
            oldBinaryDictionary.close();
        }
        if (mBinaryDictionary.isValidDictionary()
                && needsToMigrateDictionary(mBinaryDictionary.getFormatVersion())) {
            mBinaryDictionary.migrateTo(DICTIONARY_FORMAT_VERSION);
        }
    }

    /**
+27 −0
Original line number Diff line number Diff line
@@ -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();
@@ -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()];
+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();
    }
}