Merge "Change scopes of some methods in DynamicBinaryDictIOUtils."
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 6ec7aee..29c6c04 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -115,7 +115,7 @@
     private static native long openNative(String sourceDir, long dictOffset, long dictSize,
             boolean isUpdatable);
     private static native void flushNative(long dict, String filePath);
-    private static native boolean needsToRunGCNative(long dict);
+    private static native boolean needsToRunGCNative(long dict, boolean mindsBlockByGC);
     private static native void flushWithGCNative(long dict, String filePath);
     private static native void closeNative(long dict);
     private static native int getProbabilityNative(long dict, int[] word);
@@ -270,7 +270,7 @@
     }
 
     private void runGCIfRequired() {
-        if (needsToRunGCNative(mNativeDict)) {
+        if (needsToRunGC(true /* mindsBlockByGC */)) {
             flushWithGC();
         }
     }
@@ -326,9 +326,15 @@
         reopen();
     }
 
-    public boolean needsToRunGC() {
+    /**
+     * Checks whether GC is needed to run or not.
+     * @param mindsBlockByGC Whether to mind operations blocked by GC. We don't need to care about
+     * the blocking in some situations such as in idle time or just before closing.
+     * @return whether GC is needed to run or not.
+     */
+    public boolean needsToRunGC(final boolean mindsBlockByGC) {
         if (!isValidDictionary()) return false;
-        return needsToRunGCNative(mNativeDict);
+        return needsToRunGCNative(mNativeDict, mindsBlockByGC);
     }
 
     @UsedForTesting
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index cbba3f8..2d1ca51 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -505,7 +505,7 @@
                     BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(),
                             DICTIONARY_FORMAT_VERSION, getHeaderAttributeMap());
                 } else {
-                    if (mBinaryDictionary.needsToRunGC()) {
+                    if (mBinaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) {
                         mBinaryDictionary.flushWithGC();
                     } else {
                         mBinaryDictionary.flush();
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 85e100e..c5ef264 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -113,10 +113,10 @@
 }
 
 static bool latinime_BinaryDictionary_needsToRunGC(JNIEnv *env, jclass clazz,
-        jlong dict) {
+        jlong dict, jboolean mindsBlockByGC) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     if (!dictionary) return false;
-    return dictionary->needsToRunGC();
+    return dictionary->needsToRunGC(mindsBlockByGC == JNI_TRUE);
 }
 
 static void latinime_BinaryDictionary_flushWithGC(JNIEnv *env, jclass clazz, jlong dict,
@@ -364,7 +364,7 @@
     },
     {
         const_cast<char *>("needsToRunGCNative"),
-        const_cast<char *>("(J)Z"),
+        const_cast<char *>("(JZ)Z"),
         reinterpret_cast<void *>(latinime_BinaryDictionary_needsToRunGC)
     },
     {
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 9b4c91a..b1d01ed 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -123,8 +123,8 @@
     mDictionaryStructureWithBufferPolicy->flushWithGC(filePath);
 }
 
-bool Dictionary::needsToRunGC() {
-    return mDictionaryStructureWithBufferPolicy->needsToRunGC();
+bool Dictionary::needsToRunGC(const bool mindsBlockByGC) {
+    return mDictionaryStructureWithBufferPolicy->needsToRunGC(mindsBlockByGC);
 }
 
 void Dictionary::getProperty(const char *const query, char *const outResult,
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 5740508..d8a0f3e 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -81,7 +81,7 @@
 
     void flushWithGC(const char *const filePath);
 
-    bool needsToRunGC();
+    bool needsToRunGC(const bool mindsBlockByGC);
 
     void getProperty(const char *const query, char *const outResult,
             const int maxResultLength) const;
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index 2434287..c7ffef0 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -78,7 +78,7 @@
 
     virtual void flushWithGC(const char *const filePath) = 0;
 
-    virtual bool needsToRunGC() const = 0;
+    virtual bool needsToRunGC(const bool mindsBlockByGC) const = 0;
 
     virtual void getProperty(const char *const query, char *const outResult,
             const int maxResultLength) const = 0;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp
index 5eb4733..5f755c3 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp
@@ -41,7 +41,7 @@
             return false;
         }
     } else {
-        valueStack.back() += 1;
+        mValueStack.back() += 1;
         if (node->isTerminal()) {
             mValidUnigramCount += 1;
         }
@@ -49,6 +49,23 @@
     return true;
 }
 
+bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToUpdateBigramProbability
+        ::onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+                const int *const nodeCodePoints) {
+    if (!node->isDeleted()) {
+        int pos = node->getBigramsPos();
+        if (pos != NOT_A_DICT_POS) {
+            int bigramEntryCount = 0;
+            if (!mBigramPolicy->updateAllBigramEntriesAndDeleteUselessEntries(&pos,
+                    &bigramEntryCount)) {
+                return false;
+            }
+            mValidBigramEntryCount += bigramEntryCount;
+        }
+    }
+    return true;
+}
+
 // Writes dummy PtNode array size when the head of PtNode array is read.
 bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
         ::onDescend(const int ptNodeArrayPos) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h
index aa6e609..3019988 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h
@@ -40,22 +40,22 @@
         TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted(
                 DynamicPatriciaTrieWritingHelper *const writingHelper,
                 BufferWithExtendableBuffer *const buffer)
-                : mWritingHelper(writingHelper), mBuffer(buffer), valueStack(),
+                : mWritingHelper(writingHelper), mBuffer(buffer), mValueStack(),
                   mChildrenValue(0), mValidUnigramCount(0) {}
 
         ~TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted() {};
 
         bool onAscend() {
-            if (valueStack.empty()) {
+            if (mValueStack.empty()) {
                 return false;
             }
-            mChildrenValue = valueStack.back();
-            valueStack.pop_back();
+            mChildrenValue = mValueStack.back();
+            mValueStack.pop_back();
             return true;
         }
 
         bool onDescend(const int ptNodeArrayPos) {
-            valueStack.push_back(0);
+            mValueStack.push_back(0);
             return true;
         }
 
@@ -74,7 +74,7 @@
 
         DynamicPatriciaTrieWritingHelper *const mWritingHelper;
         BufferWithExtendableBuffer *const mBuffer;
-        std::vector<int> valueStack;
+        std::vector<int> mValueStack;
         int mChildrenValue;
         int mValidUnigramCount;
     };
@@ -94,20 +94,7 @@
         bool onReadingPtNodeArrayTail() { return true; }
 
         bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
-                const int *const nodeCodePoints) {
-            if (!node->isDeleted()) {
-                int pos = node->getBigramsPos();
-                if (pos != NOT_A_DICT_POS) {
-                    int bigramEntryCount = 0;
-                    if (!mBigramPolicy->updateAllBigramEntriesAndDeleteUselessEntries(&pos,
-                            &bigramEntryCount)) {
-                        return false;
-                    }
-                    mValidBigramEntryCount += bigramEntryCount;
-                }
-            }
-            return true;
-        }
+                const int *const nodeCodePoints);
 
         int getValidBigramEntryCount() const {
             return mValidBigramEntryCount;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
index 4581ec0..8c0890e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
@@ -291,7 +291,7 @@
     writingHelper.writeToDictFileWithGC(getRootPosition(), filePath, &mHeaderPolicy);
 }
 
-bool DynamicPatriciaTriePolicy::needsToRunGC() const {
+bool DynamicPatriciaTriePolicy::needsToRunGC(const bool mindsBlockByGC) const {
     if (!mBuffer->isUpdatable()) {
         AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary.");
         return false;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
index 7f9d4d9..bdb436c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
@@ -91,7 +91,7 @@
 
     void flushWithGC(const char *const filePath);
 
-    bool needsToRunGC() const;
+    bool needsToRunGC(const bool mindsBlockByGC) const;
 
     void getProperty(const char *const query, char *const outResult,
             const int maxResultLength) const;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp
index bae5e8c..2a2e9bc 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp
@@ -147,7 +147,7 @@
         const HeaderPolicy *const headerPolicy, const int unigramCount, const int bigramCount) {
     BufferWithExtendableBuffer headerBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */);
     const int extendedRegionSize = headerPolicy->getExtendedRegionSize() +
-            mBuffer->getTailPosition() - mBuffer->getOriginalBufferSize();
+            mBuffer->getUsedAdditionalBufferSize();
     if (!headerPolicy->writeHeaderToBuffer(&headerBuffer, false /* updatesLastUpdatedTime */,
             unigramCount, bigramCount, extendedRegionSize)) {
         return;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
index 78c6c04..9ce9994 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
@@ -20,7 +20,8 @@
 
 // Note that these are corresponding definitions in Java side in FormatSpec.FileHeader.
 const char *const HeaderPolicy::MULTIPLE_WORDS_DEMOTION_RATE_KEY = "MULTIPLE_WORDS_DEMOTION_RATE";
-const char *const HeaderPolicy::USES_FORGETTING_CURVE_KEY = "USES_FORGETTING_CURVE";
+// TODO: Change attribute string to "IS_DECAYING_DICT".
+const char *const HeaderPolicy::IS_DECAYING_DICT_KEY = "USES_FORGETTING_CURVE";
 const char *const HeaderPolicy::LAST_UPDATED_TIME_KEY = "date";
 const char *const HeaderPolicy::UNIGRAM_COUNT_KEY = "UNIGRAM_COUNT";
 const char *const HeaderPolicy::BIGRAM_COUNT_KEY = "BIGRAM_COUNT";
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 93b9c6f..4261667 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
@@ -36,8 +36,8 @@
               mSize(HeaderReadWriteUtils::getHeaderSize(dictBuf)),
               mAttributeMap(createAttributeMapAndReadAllAttributes(dictBuf)),
               mMultiWordCostMultiplier(readMultipleWordCostMultiplier()),
-              mUsesForgettingCurve(HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap,
-                      USES_FORGETTING_CURVE_KEY, false /* defaultValue */)),
+              mIsDecayingDict(HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap,
+                      IS_DECAYING_DICT_KEY, false /* defaultValue */)),
               mLastUpdatedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
                       LAST_UPDATED_TIME_KEY, time(0) /* defaultValue */)),
               mUnigramCount(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
@@ -54,8 +54,8 @@
               mDictionaryFlags(HeaderReadWriteUtils::createAndGetDictionaryFlagsUsingAttributeMap(
                       attributeMap)), mSize(0), mAttributeMap(*attributeMap),
               mMultiWordCostMultiplier(readMultipleWordCostMultiplier()),
-              mUsesForgettingCurve(HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap,
-                      USES_FORGETTING_CURVE_KEY, false /* defaultValue */)),
+              mIsDecayingDict(HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap,
+                      IS_DECAYING_DICT_KEY, false /* defaultValue */)),
               mLastUpdatedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
                       LAST_UPDATED_TIME_KEY, time(0) /* defaultValue */)),
               mUnigramCount(0), mBigramCount(0), mExtendedRegionSize(0) {}
@@ -82,8 +82,8 @@
         return mMultiWordCostMultiplier;
     }
 
-    AK_FORCE_INLINE bool usesForgettingCurve() const {
-        return mUsesForgettingCurve;
+    AK_FORCE_INLINE bool isDecayingDict() const {
+        return mIsDecayingDict;
     }
 
     AK_FORCE_INLINE int getLastUpdatedTime() const {
@@ -113,7 +113,7 @@
     DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderPolicy);
 
     static const char *const MULTIPLE_WORDS_DEMOTION_RATE_KEY;
-    static const char *const USES_FORGETTING_CURVE_KEY;
+    static const char *const IS_DECAYING_DICT_KEY;
     static const char *const LAST_UPDATED_TIME_KEY;
     static const char *const UNIGRAM_COUNT_KEY;
     static const char *const BIGRAM_COUNT_KEY;
@@ -126,7 +126,7 @@
     const int mSize;
     HeaderReadWriteUtils::AttributeMap mAttributeMap;
     const float mMultiWordCostMultiplier;
-    const bool mUsesForgettingCurve;
+    const bool mIsDecayingDict;
     const int mLastUpdatedTime;
     const int mUnigramCount;
     const int mBigramCount;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
index 4277ff5..8d88c68 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
@@ -107,7 +107,7 @@
         AKLOGI("Warning: flushWithGC() is called for non-updatable dictionary.");
     }
 
-    bool needsToRunGC() const {
+    bool needsToRunGC(const bool mindsBlockByGC) const {
         // This method should not be called for non-updatable dictionary.
         AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary.");
         return false;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
index 17d2e39..9dc3482 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
@@ -42,6 +42,10 @@
         return mOriginalBufferSize + mUsedAdditionalBufferSize;
     }
 
+    AK_FORCE_INLINE int getUsedAdditionalBufferSize() const {
+        return mUsedAdditionalBufferSize;
+    }
+
     /**
      * For reading.
      */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
index 4fae919..f22e94c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
@@ -96,7 +96,7 @@
         fclose(file);
         return false;
     }
-    const int additionalBufSize = buffer->getTailPosition() - buffer->getOriginalBufferSize();
+    const int additionalBufSize = buffer->getUsedAdditionalBufferSize();
     if (additionalBufSize > 0 && fwrite(buffer->getBuffer(true /* usesAdditionalBuffer */),
             additionalBufSize, 1, file) < 1) {
         fclose(file);
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
index 826c0f7..6a21522 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
@@ -606,7 +606,7 @@
             binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
                     0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
                     Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
-            while(!binaryDictionary.needsToRunGC()) {
+            while(!binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) {
                 final String word = CodePointUtils.generateWord(random, codePointSet);
                 words.add(word);
                 final int unigramProbability = random.nextInt(0xFF);
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
index 6c4cbcf..bd06e9f 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
@@ -80,17 +80,17 @@
     }
 
     /**
-     * Returns a decrypted/uncompressed binary dictionary.
+     * Returns a decrypted/uncompressed dictionary.
      *
-     * This will decrypt/uncompress any number of times as necessary until it finds the binary
+     * This will decrypt/uncompress any number of times as necessary until it finds the
      * dictionary signature, and copy the decoded file to a temporary place.
-     * If this is not a binary dictionary, the method returns null.
+     * If this is not a dictionary, the method returns null.
      */
-    public static DecoderChainSpec getRawBinaryDictionaryOrNull(final File src) {
-        return getRawBinaryDictionaryOrNullInternal(new DecoderChainSpec(), src, 0);
+    public static DecoderChainSpec getRawDictionaryOrNull(final File src) {
+        return getRawDictionaryOrNullInternal(new DecoderChainSpec(), src, 0);
     }
 
-    private static DecoderChainSpec getRawBinaryDictionaryOrNullInternal(
+    private static DecoderChainSpec getRawDictionaryOrNullInternal(
             final DecoderChainSpec spec, final File src, final int depth) {
         // Unfortunately the decoding scheme we use can consider any data to be encrypted
         // and will product some output, meaning it's not possible to reliably detect encrypted
@@ -98,7 +98,8 @@
         // over and over, ending in a stack overflow. Hence we limit the depth at which we try
         // decoding the file.
         if (depth > MAX_DECODE_DEPTH) return null;
-        if (BinaryDictDecoderUtils.isBinaryDictionary(src)) {
+        if (BinaryDictDecoderUtils.isBinaryDictionary(src)
+                || CombinedInputOutput.isCombinedDictionary(src.getAbsolutePath())) {
             spec.mFile = src;
             return spec;
         }
@@ -106,7 +107,7 @@
         final File uncompressedFile = tryGetUncompressedFile(src);
         if (null != uncompressedFile) {
             final DecoderChainSpec newSpec =
-                    getRawBinaryDictionaryOrNullInternal(spec, uncompressedFile, depth + 1);
+                    getRawDictionaryOrNullInternal(spec, uncompressedFile, depth + 1);
             if (null == newSpec) return null;
             return newSpec.addStep(COMPRESSION);
         }
@@ -114,7 +115,7 @@
         final File decryptedFile = tryGetDecryptedFile(src);
         if (null != decryptedFile) {
             final DecoderChainSpec newSpec =
-                    getRawBinaryDictionaryOrNullInternal(spec, decryptedFile, depth + 1);
+                    getRawDictionaryOrNullInternal(spec, decryptedFile, depth + 1);
             if (null == newSpec) return null;
             return newSpec.addStep(ENCRYPTION);
         }
@@ -175,15 +176,16 @@
                 return XmlDictInputOutput.readDictionaryXml(
                         new BufferedInputStream(new FileInputStream(file)),
                         null /* shortcuts */, null /* bigrams */);
-            } else if (CombinedInputOutput.isCombinedDictionary(filename)) {
-                if (report) System.out.println("Format : Combined format");
-                return CombinedInputOutput.readDictionaryCombined(
-                        new BufferedInputStream(new FileInputStream(file)));
             } else {
-                final DecoderChainSpec decodedSpec = getRawBinaryDictionaryOrNull(file);
+                final DecoderChainSpec decodedSpec = getRawDictionaryOrNull(file);
                 if (null == decodedSpec) {
                     crash(filename, new RuntimeException(
                             filename + " does not seem to be a dictionary file"));
+                } else if (CombinedInputOutput.isCombinedDictionary(
+                        decodedSpec.mFile.getAbsolutePath())){
+                    if (report) System.out.println("Format : Combined format");
+                    return CombinedInputOutput.readDictionaryCombined(
+                            new BufferedInputStream(new FileInputStream(decodedSpec.mFile)));
                 } else {
                     final DictDecoder dictDecoder = FormatSpec.getDictDecoder(decodedSpec.mFile,
                             DictDecoder.USE_BYTEARRAY);
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
index 9274dcd..dff3387 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
@@ -79,7 +79,7 @@
                 throw new RuntimeException("Too many/too few arguments for command " + COMMAND);
             }
             final BinaryDictOffdeviceUtils.DecoderChainSpec decodedSpec =
-                    BinaryDictOffdeviceUtils.getRawBinaryDictionaryOrNull(new File(mArgs[0]));
+                    BinaryDictOffdeviceUtils.getRawDictionaryOrNull(new File(mArgs[0]));
             if (null == decodedSpec) {
                 System.out.println(mArgs[0] + " does not seem to be a dictionary");
                 return;
diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
index 1eff497..1baeb7a 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
@@ -64,7 +64,7 @@
 
         // Test for an actually compressed dictionary and its contents
         final BinaryDictOffdeviceUtils.DecoderChainSpec decodeSpec =
-                BinaryDictOffdeviceUtils.getRawBinaryDictionaryOrNull(dst);
+                BinaryDictOffdeviceUtils.getRawDictionaryOrNull(dst);
         for (final String step : decodeSpec.mDecoderSpec) {
             assertEquals("Wrong decode spec", BinaryDictOffdeviceUtils.COMPRESSION, step);
         }
@@ -90,7 +90,7 @@
 
         // Test that a random data file actually fails
         assertNull("Wrongly identified data file",
-                BinaryDictOffdeviceUtils.getRawBinaryDictionaryOrNull(dst));
+                BinaryDictOffdeviceUtils.getRawDictionaryOrNull(dst));
 
         final File gzDst = File.createTempFile("testGetRawDict", ".tmp");
         gzDst.deleteOnExit();
@@ -103,6 +103,6 @@
 
         // Test that a compressed random data file actually fails
         assertNull("Wrongly identified data file",
-                BinaryDictOffdeviceUtils.getRawBinaryDictionaryOrNull(gzDst));
+                BinaryDictOffdeviceUtils.getRawDictionaryOrNull(gzDst));
     }
 }