Merge "Fix: Reporting wrong main dictionary availability."
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index 063f211..fc3b48c 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -26,7 +26,6 @@
 import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
 import android.support.v4.view.accessibility.AccessibilityRecordCompat;
 import android.util.Log;
-import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
@@ -37,9 +36,10 @@
 import com.android.inputmethod.keyboard.KeyboardView;
 import com.android.inputmethod.latin.settings.Settings;
 import com.android.inputmethod.latin.settings.SettingsValues;
-import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.latin.utils.CoordinateUtils;
 
+import java.util.List;
+
 /**
  * Exposes a virtual view sub-tree for {@link KeyboardView} and generates
  * {@link AccessibilityEvent}s for individual {@link Key}s.
@@ -58,9 +58,6 @@
     private final KeyCodeDescriptionMapper mKeyCodeDescriptionMapper;
     private final AccessibilityUtils mAccessibilityUtils;
 
-    /** A map of integer IDs to {@link Key}s. */
-    private final SparseArray<Key> mVirtualViewIdToKey = CollectionUtils.newSparseArray();
-
     /** Temporary rect used to calculate in-screen bounds. */
     private final Rect mTempBoundsInScreen = new Rect();
 
@@ -73,6 +70,9 @@
     /** The current keyboard view. */
     private KeyboardView mKeyboardView;
 
+    /** The current keyboard. */
+    private Keyboard mKeyboard;
+
     public AccessibilityEntityProvider(final KeyboardView keyboardView,
             final InputMethodService inputMethod) {
         mInputMethodService = inputMethod;
@@ -92,14 +92,43 @@
 
         // Since this class is constructed lazily, we might not get a subsequent
         // call to setKeyboard() and therefore need to call it now.
-        setKeyboard();
+        setKeyboard(keyboardView.getKeyboard());
     }
 
     /**
      * Sets the keyboard represented by this node provider.
+     *
+     * @param keyboard The keyboard that is being set to the keyboard view.
      */
-    public void setKeyboard() {
-        assignVirtualViewIds();
+    public void setKeyboard(final Keyboard keyboard) {
+        mKeyboard = keyboard;
+    }
+
+    private Key getKeyOf(final int virtualViewId) {
+        if (mKeyboard == null) {
+            return null;
+        }
+        final List<Key> sortedKeys = mKeyboard.getSortedKeys();
+        // Use a virtual view id as an index of the sorted keys list.
+        if (virtualViewId >= 0 && virtualViewId < sortedKeys.size()) {
+            return sortedKeys.get(virtualViewId);
+        }
+        return null;
+    }
+
+    private int getVirtualViewIdOf(final Key key) {
+        if (mKeyboard == null) {
+            return View.NO_ID;
+        }
+        final List<Key> sortedKeys = mKeyboard.getSortedKeys();
+        final int size = sortedKeys.size();
+        for (int index = 0; index < size; index++) {
+            if (sortedKeys.get(index) == key) {
+                // Use an index of the sorted keys list as a virtual view id.
+                return index;
+            }
+        }
+        return View.NO_ID;
     }
 
     /**
@@ -112,7 +141,7 @@
      * @see AccessibilityEvent
      */
     public AccessibilityEvent createAccessibilityEvent(final Key key, final int eventType) {
-        final int virtualViewId = generateVirtualViewIdForKey(key);
+        final int virtualViewId = getVirtualViewIdOf(key);
         final String keyDescription = getKeyDescription(key);
         final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
         event.setPackageName(mKeyboardView.getContext().getPackageName());
@@ -158,16 +187,21 @@
             ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo);
 
             // Add the virtual children of the root View.
-            final Keyboard keyboard = mKeyboardView.getKeyboard();
-            for (final Key key : keyboard.getSortedKeys()) {
-                final int childVirtualViewId = generateVirtualViewIdForKey(key);
-                rootInfo.addChild(mKeyboardView, childVirtualViewId);
+            final List<Key> sortedKeys = mKeyboard.getSortedKeys();
+            final int size = sortedKeys.size();
+            for (int index = 0; index < size; index++) {
+                final Key key = sortedKeys.get(index);
+                if (key.isSpacer()) {
+                    continue;
+                }
+                // Use an index of the sorted keys list as a virtual view id.
+                rootInfo.addChild(mKeyboardView, index);
             }
             return rootInfo;
         }
 
-        // Find the view that corresponds to the given id.
-        final Key key = mVirtualViewIdToKey.get(virtualViewId);
+        // Find the key that corresponds to the given virtual view id.
+        final Key key = getKeyOf(virtualViewId);
         if (key == null) {
             Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
             return null;
@@ -226,7 +260,7 @@
     @Override
     public boolean performAction(final int virtualViewId, final int action,
             final Bundle arguments) {
-        final Key key = mVirtualViewIdToKey.get(virtualViewId);
+        final Key key = getKeyOf(virtualViewId);
         if (key == null) {
             return false;
         }
@@ -242,7 +276,7 @@
      * @return The result of performing the action, or false if the action is not supported.
      */
     boolean performActionForKey(final Key key, final int action, final Bundle arguments) {
-        final int virtualViewId = generateVirtualViewIdForKey(key);
+        final int virtualViewId = getVirtualViewIdOf(key);
 
         switch (action) {
         case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
@@ -288,7 +322,7 @@
         final boolean shouldObscure = mAccessibilityUtils.shouldObscureInput(editorInfo);
         final SettingsValues currentSettings = Settings.getInstance().getCurrent();
         final String keyCodeDescription = mKeyCodeDescriptionMapper.getDescriptionForKey(
-                mKeyboardView.getContext(), mKeyboardView.getKeyboard(), key, shouldObscure);
+                mKeyboardView.getContext(), mKeyboard, key, shouldObscure);
         if (currentSettings.isWordSeparator(key.getCode())) {
             return mAccessibilityUtils.getAutoCorrectionDescription(
                     keyCodeDescription, shouldObscure);
@@ -298,39 +332,9 @@
     }
 
     /**
-     * Assigns virtual view IDs to keyboard keys and populates the related maps.
-     */
-    private void assignVirtualViewIds() {
-        final Keyboard keyboard = mKeyboardView.getKeyboard();
-        if (keyboard == null) {
-            return;
-        }
-        mVirtualViewIdToKey.clear();
-
-        for (final Key key : keyboard.getSortedKeys()) {
-            final int virtualViewId = generateVirtualViewIdForKey(key);
-            mVirtualViewIdToKey.put(virtualViewId, key);
-        }
-    }
-
-    /**
      * Updates the parent's on-screen location.
      */
     private void updateParentLocation() {
         mKeyboardView.getLocationOnScreen(mParentLocation);
     }
-
-    /**
-     * Generates a virtual view identifier for the given key. Returned
-     * identifiers are valid until the next global layout state change.
-     *
-     * @param key The key to identify.
-     * @return A virtual view identifier.
-     */
-    private static int generateVirtualViewIdForKey(final Key key) {
-        // The key x- and y-coordinates are stable between layout changes.
-        // Generate an identifier by bit-shifting the x-coordinate to the
-        // left-half of the integer and OR'ing with the y-coordinate.
-        return ((0xFFFF & key.getX()) << (Integer.SIZE / 2)) | (0xFFFF & key.getY());
-    }
 }
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
index 0043b78..c8fbb3d 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -55,6 +55,7 @@
 
     private InputMethodService mInputMethod;
     private MainKeyboardView mView;
+    private Keyboard mKeyboard;
     private AccessibilityEntityProvider mAccessibilityNodeProvider;
 
     private Key mLastHoverKey = null;
@@ -66,6 +67,7 @@
 
     /** The most recently set keyboard mode. */
     private int mLastKeyboardMode;
+    private static final int NOT_A_KEYBOARD_MODE = -1;
 
     public static void init(final InputMethodService inputMethod) {
         sInstance.initInternal(inputMethod);
@@ -104,6 +106,10 @@
             return;
         }
         mAccessibilityNodeProvider.setView(view);
+
+        // Since this class is constructed lazily, we might not get a subsequent
+        // call to setKeyboard() and therefore need to call it now.
+        setKeyboard(view.getKeyboard());
     }
 
     /**
@@ -111,15 +117,17 @@
      * <p>
      * <b>Note:</b> This method will be called even if accessibility is not
      * enabled.
+     * @param keyboard The keyboard that is being set to the wrapping view.
      */
-    public void setKeyboard() {
-        if (mView == null) {
+    public void setKeyboard(final Keyboard keyboard) {
+        if (keyboard == null) {
             return;
         }
+        mKeyboard = keyboard;
         if (mAccessibilityNodeProvider != null) {
-            mAccessibilityNodeProvider.setKeyboard();
+            mAccessibilityNodeProvider.setKeyboard(keyboard);
         }
-        final int keyboardMode = mView.getKeyboard().mId.mMode;
+        final int keyboardMode = keyboard.mId.mMode;
 
         // Since this method is called even when accessibility is off, make sure
         // to check the state before announcing anything. Also, don't announce
@@ -139,7 +147,7 @@
             return;
         }
         announceKeyboardHidden();
-        mLastKeyboardMode = -1;
+        mLastKeyboardMode = NOT_A_KEYBOARD_MODE;
     }
 
     /**
@@ -148,7 +156,7 @@
      *
      * @param mode The new keyboard mode.
      */
-    private void announceKeyboardMode(int mode) {
+    private void announceKeyboardMode(final int mode) {
         final int resId = KEYBOARD_MODE_RES_IDS.get(mode);
         if (resId == 0) {
             return;
@@ -329,12 +337,11 @@
      * Notifies the user of changes in the keyboard shift state.
      */
     public void notifyShiftState() {
-        if (mView == null) {
+        if (mView == null || mKeyboard == null) {
             return;
         }
 
-        final Keyboard keyboard = mView.getKeyboard();
-        final KeyboardId keyboardId = keyboard.mId;
+        final KeyboardId keyboardId = mKeyboard.mId;
         final int elementId = keyboardId.mElementId;
         final Context context = mView.getContext();
         final CharSequence text;
@@ -359,14 +366,13 @@
      * Notifies the user of changes in the keyboard symbols state.
      */
     public void notifySymbolsState() {
-        if (mView == null) {
+        if (mView == null || mKeyboard == null) {
             return;
         }
 
-        final Keyboard keyboard = mView.getKeyboard();
-        final Context context = mView.getContext();
-        final KeyboardId keyboardId = keyboard.mId;
+        final KeyboardId keyboardId = mKeyboard.mId;
         final int elementId = keyboardId.mElementId;
+        final Context context = mView.getContext();
         final int resId;
 
         switch (elementId) {
@@ -388,12 +394,9 @@
             resId = R.string.spoken_description_mode_phone_shift;
             break;
         default:
-            resId = -1;
-        }
-
-        if (resId < 0) {
             return;
         }
+
         final String text = context.getString(resId);
         AccessibilityUtils.getInstance().announceForAccessibility(mView, text);
     }
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 1cafd41..ecef8cc 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -406,7 +406,7 @@
 
         // This always needs to be set since the accessibility state can
         // potentially change without the keyboard being set again.
-        AccessibleKeyboardViewProxy.getInstance().setKeyboard();
+        AccessibleKeyboardViewProxy.getInstance().setKeyboard(keyboard);
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 3746d5b..c89bda4 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -118,10 +118,11 @@
         final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
         Arrays.fill(proximityCharsArray, Constants.NOT_A_CODE);
         for (int i = 0; i < mGridSize; ++i) {
-            final int proximityCharsLength = gridNeighborKeys[i].size();
+            final List<Key> neighborKeys = gridNeighborKeys[i];
+            final int proximityCharsLength = neighborKeys.size();
             int infoIndex = i * MAX_PROXIMITY_CHARS_SIZE;
             for (int j = 0; j < proximityCharsLength; ++j) {
-                final Key neighborKey = gridNeighborKeys[i].get(j);
+                final Key neighborKey = neighborKeys.get(j);
                 // Excluding from proximityCharsArray
                 if (!needsProximityInfo(neighborKey)) {
                     continue;
@@ -359,11 +360,11 @@
         for (int i = 0; i < gridSize; ++i) {
             final int indexStart = i * keyCount;
             final int indexEnd = indexStart + neighborCountPerCell[i];
-            final ArrayList<Key> neighbords = CollectionUtils.newArrayList(indexEnd - indexStart);
+            final ArrayList<Key> neighbors = CollectionUtils.newArrayList(indexEnd - indexStart);
             for (int index = indexStart; index < indexEnd; index++) {
-                neighbords.add(neighborsFlatBuffer[index]);
+                neighbors.add(neighborsFlatBuffer[index]);
             }
-            mGridNeighbors[i] = Collections.unmodifiableList(neighbords);
+            mGridNeighbors[i] = Collections.unmodifiableList(neighbors);
         }
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
index 397c098..67a2227 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -213,8 +213,7 @@
             if (mCachedGridKeys != null) {
                 return mCachedGridKeys;
             }
-            final ArrayList<Key> cachedKeys = CollectionUtils.newArrayList(mGridKeys.size());
-            cachedKeys.addAll(mGridKeys);
+            final ArrayList<Key> cachedKeys = new ArrayList<Key>(mGridKeys);
             mCachedGridKeys = Collections.unmodifiableList(cachedKeys);
             return mCachedGridKeys;
         }
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index a351ee9..b88509f 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -41,6 +41,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map;
 
 /**
  * Implements a static, compacted, binary dictionary of standard words.
@@ -123,8 +124,7 @@
     }
 
     /**
-     * Constructor for the binary dictionary. This is supposed to be called from the
-     * dictionary factory.
+     * Constructs binary dictionary using existing dictionary file.
      * @param filename the name of the file to read through native code.
      * @param offset the offset of the dictionary data within the file.
      * @param length the length of the binary data.
@@ -145,6 +145,38 @@
         loadDictionary(filename, offset, length, isUpdatable);
     }
 
+    /**
+     * Constructs binary dictionary on memory.
+     * @param filename the name of the file used to flush.
+     * @param useFullEditDistance whether to use the full edit distance in suggestions
+     * @param dictType the dictionary type, as a human-readable string
+     * @param formatVersion the format version of the dictionary
+     * @param attributeMap the attributes of the dictionary
+     */
+    @UsedForTesting
+    public BinaryDictionary(final String filename, final boolean useFullEditDistance,
+            final Locale locale, final String dictType, final long formatVersion,
+            final Map<String, String> attributeMap) {
+        super(dictType);
+        mLocale = locale;
+        mDictSize = 0;
+        mDictFilePath = filename;
+        // On memory dictionary is always updatable.
+        mIsUpdatable = true;
+        mHasUpdated = false;
+        mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance);
+        final String[] keyArray = new String[attributeMap.size()];
+        final String[] valueArray = new String[attributeMap.size()];
+        int index = 0;
+        for (final String key : attributeMap.keySet()) {
+            keyArray[index] = key;
+            valueArray[index] = attributeMap.get(key);
+            index++;
+        }
+        mNativeDict = createOnMemoryNative(formatVersion, locale.toString(), keyArray, valueArray);
+    }
+
+
     static {
         JniUtils.loadNativeLibrary();
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
index ab943a3..251a719 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
@@ -99,6 +99,27 @@
               mMaxBigramCount(HeaderReadWriteUtils::readIntAttributeValue(
                       &mAttributeMap, MAX_BIGRAM_COUNT_KEY, DEFAULT_MAX_BIGRAM_COUNT)) {}
 
+    // Copy header information
+    HeaderPolicy(const HeaderPolicy *const headerPolicy)
+            : mDictFormatVersion(headerPolicy->mDictFormatVersion),
+              mDictionaryFlags(headerPolicy->mDictionaryFlags), mSize(headerPolicy->mSize),
+              mAttributeMap(headerPolicy->mAttributeMap), mLocale(headerPolicy->mLocale),
+              mMultiWordCostMultiplier(headerPolicy->mMultiWordCostMultiplier),
+              mRequiresGermanUmlautProcessing(headerPolicy->mRequiresGermanUmlautProcessing),
+              mIsDecayingDict(headerPolicy->mIsDecayingDict),
+              mDate(headerPolicy->mDate), mLastDecayedTime(headerPolicy->mLastDecayedTime),
+              mUnigramCount(headerPolicy->mUnigramCount), mBigramCount(headerPolicy->mBigramCount),
+              mExtendedRegionSize(headerPolicy->mExtendedRegionSize),
+              mHasHistoricalInfoOfWords(headerPolicy->mHasHistoricalInfoOfWords),
+              mForgettingCurveOccurrencesToLevelUp(
+                      headerPolicy->mForgettingCurveOccurrencesToLevelUp),
+              mForgettingCurveProbabilityValuesTableId(
+                      headerPolicy->mForgettingCurveProbabilityValuesTableId),
+              mForgettingCurveDurationToLevelDown(
+                      headerPolicy->mForgettingCurveDurationToLevelDown),
+              mMaxUnigramCount(headerPolicy->mMaxUnigramCount),
+              mMaxBigramCount(headerPolicy->mMaxBigramCount) {}
+
     // Temporary dummy header.
     HeaderPolicy()
             : mDictFormatVersion(FormatUtils::UNKNOWN_VERSION), mDictionaryFlags(0), mSize(0),
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
index eefedc3..be7e43b 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
@@ -19,10 +19,12 @@
 #include <climits>
 
 #include "defines.h"
+#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h"
 #include "suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h"
 #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h"
 #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h"
+#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
 #include "suggest/policyimpl/dictionary/utils/file_utils.h"
 #include "suggest/policyimpl/dictionary/utils/format_utils.h"
 #include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
@@ -56,6 +58,11 @@
             Ver4DictBuffers::Ver4DictBuffersPtr dictBuffers =
                     Ver4DictBuffers::createVer4DictBuffers(&headerPolicy,
                             Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE);
+            if (!DynamicPtWritingUtils::writeEmptyDictionary(
+                    dictBuffers->getWritableTrieBuffer(), 0 /* rootPos */)) {
+                AKLOGE("Empty ver4 dictionary structure cannot be created on memory.");
+                return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr);
+            }
             return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(
                     new Ver4PatriciaTriePolicy(std::move(dictBuffers)));
         }
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 eda882d..95f6544 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
@@ -131,7 +131,7 @@
           mIsUpdatable(isUpdatable) {}
 
 Ver4DictBuffers::Ver4DictBuffers(const HeaderPolicy *const headerPolicy, const int maxTrieSize)
-        : mHeaderBuffer(nullptr), mDictBuffer(nullptr), mHeaderPolicy(),
+        : mHeaderBuffer(nullptr), mDictBuffer(nullptr), mHeaderPolicy(headerPolicy),
           mExpandableHeaderBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE),
           mExpandableTrieBuffer(maxTrieSize), mTerminalPositionLookupTable(),
           mProbabilityDictContent(headerPolicy->hasHistoricalInfoOfWords()),
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
index b476627..0fb0fa5 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
@@ -97,6 +97,37 @@
         binaryDictionary.close();
     }
 
+    public void testConstructingDictionaryOnMemory() {
+        testConstructingDictionaryOnMemory(FormatSpec.VERSION4);
+    }
+
+    private void testConstructingDictionaryOnMemory(final int formatVersion) {
+        File dictFile = null;
+        try {
+            dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion);
+        } catch (IOException e) {
+            fail("IOException while writing an initial dictionary : " + e);
+        }
+        FileUtils.deleteRecursively(dictFile);
+        assertFalse(dictFile.exists());
+        BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+                true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, formatVersion,
+                new HashMap<String, String>());
+        assertTrue(binaryDictionary.isValidDictionary());
+        assertEquals(formatVersion, binaryDictionary.getFormatVersion());
+        final int probability = 100;
+        addUnigramWord(binaryDictionary, "word", probability);
+        assertEquals(probability, binaryDictionary.getFrequency("word"));
+        assertFalse(dictFile.exists());
+        binaryDictionary.flush();
+        assertTrue(dictFile.exists());
+        assertTrue(binaryDictionary.isValidDictionary());
+        assertEquals(formatVersion, binaryDictionary.getFormatVersion());
+        assertEquals(probability, binaryDictionary.getFrequency("word"));
+        binaryDictionary.close();
+        dictFile.delete();
+    }
+
     public void testAddTooLongWord() {
         testAddTooLongWord(FormatSpec.VERSION4);
     }