diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index c986eb2ef419d62e4ea2ea858451315036155321..60ac1ba48bfb8043097e0b5f224b6672c218df86 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -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;
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 3c1015926e3883bfd00560d53e84f3374a6e42ac..27455441f75125d979f95ecdd8893fc46ae598eb 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -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);
+        }
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
index 638830046cced8ee892904d05b0fe32af50788c0..b4658b531f047be2b87487a6d6e295c8793ed00e 100644
--- a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
@@ -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()];
diff --git a/tests/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtilsTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..d866391012a7c6e00ef4a6453fbaa2911fa9e426
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtilsTests.java
@@ -0,0 +1,92 @@
+/*
+ * 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();
+    }
+}