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

Commit 781e3df7 authored by Keisuke Kuroyanagi's avatar Keisuke Kuroyanagi Committed by Android (Google) Code Review
Browse files

Merge "Dictionary migration in Java side."

parents 35645ac3 a785fa8e
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();
    }
@@ -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);
        }
    }

    /**
+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();
    }
}