Merge "[IL48] Move onEndBatchInputAsyncInternal to InputLogic."
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
index 2ddb003..c7f0553 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
@@ -22,7 +22,6 @@
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.latin.Suggest.SuggestInitializationListener;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.personalization.PersonalizationDictionary;
 import com.android.inputmethod.latin.personalization.PersonalizationHelper;
@@ -45,7 +44,7 @@
 
     private final ConcurrentHashMap<String, Dictionary> mDictionaries =
             CollectionUtils.newConcurrentHashMap();
-    private HashSet<String> mOnlyDictionarySetForDebug = null;
+    private HashSet<String> mDictionarySubsetForDebug = null;
 
     private Dictionary mMainDictionary;
     private ContactsBinaryDictionary mContactsDictionary;
@@ -56,17 +55,51 @@
     @UsedForTesting
     private boolean mIsCurrentlyWaitingForMainDictionary = false;
 
+    public interface DictionaryInitializationListener {
+        public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable);
+    }
+
+    /**
+     * Creates instance for initialization or when the locale is changed.
+     *
+     * @param context the context
+     * @param locale the locale
+     * @param settingsValues current settings values to control what dictionaries should be used
+     * @param listener the listener
+     * @param oldDictionaryFacilitator the instance having old dictionaries. This is null when the
+     * instance is initially created.
+     */
     public DictionaryFacilitatorForSuggest(final Context context, final Locale locale,
-            final SettingsValues settingsValues, final SuggestInitializationListener listener) {
-        resetMainDict(context, locale, listener);
+            final SettingsValues settingsValues, final DictionaryInitializationListener listener,
+            final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
         mContext = context;
         mLocale = locale;
-        // initialize a debug flag for the personalization
-        if (settingsValues.mUseOnlyPersonalizationDictionaryForDebug) {
-            mOnlyDictionarySetForDebug = new HashSet<String>();
-            mOnlyDictionarySetForDebug.add(Dictionary.TYPE_PERSONALIZATION);
-        }
+        initForDebug(settingsValues);
+        reloadMainDict(context, locale, listener);
         setUserDictionary(new UserBinaryDictionary(context, locale));
+        resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues);
+    }
+
+    /**
+     * Creates instance for when the settings values have been changed.
+     *
+     * @param settingsValues the new settings values
+     * @param oldDictionaryFacilitator the instance having old dictionaries. This must not be null.
+     */
+    //
+    public DictionaryFacilitatorForSuggest(final SettingsValues settingsValues,
+            final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
+        mContext = oldDictionaryFacilitator.mContext;
+        mLocale = oldDictionaryFacilitator.mLocale;
+        initForDebug(settingsValues);
+        // Transfer main dictionary.
+        setMainDictionary(oldDictionaryFacilitator.mMainDictionary);
+        oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_MAIN);
+        // Transfer user dictionary.
+        setUserDictionary(oldDictionaryFacilitator.mUserDictionary);
+        oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER);
+        // Transfer or create additional dictionaries depending on the settings values.
+        resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues);
     }
 
     @UsedForTesting
@@ -76,8 +109,15 @@
                 false /* useFullEditDistance */, locale);
         mContext = context;
         mLocale = locale;
-        mMainDictionary = mainDict;
-        addOrReplaceDictionary(Dictionary.TYPE_MAIN, mainDict);
+        setMainDictionary(mainDict);
+    }
+
+    // initialize a debug flag for the personalization
+    private void initForDebug(final SettingsValues settingsValues) {
+        if (settingsValues.mUseOnlyPersonalizationDictionaryForDebug) {
+            mDictionarySubsetForDebug = new HashSet<String>();
+            mDictionarySubsetForDebug.add(Dictionary.TYPE_PERSONALIZATION);
+        }
     }
 
     public void close() {
@@ -86,15 +126,10 @@
         for (final Dictionary dictionary : dictionaries) {
             dictionary.close();
         }
-        mMainDictionary = null;
-        mContactsDictionary = null;
-        mUserDictionary = null;
-        mUserHistoryDictionary = null;
-        mPersonalizationDictionary = null;
     }
 
-    public void resetMainDict(final Context context, final Locale locale,
-            final SuggestInitializationListener listener) {
+    public void reloadMainDict(final Context context, final Locale locale,
+            final DictionaryInitializationListener listener) {
         mIsCurrentlyWaitingForMainDictionary = true;
         mMainDictionary = null;
         if (listener != null) {
@@ -163,12 +198,12 @@
     }
 
     /**
-     * Set dictionaries that can be turned off according to the user settings.
+     * Reset dictionaries that can be turned off according to the user settings.
      *
      * @param oldDictionaryFacilitator the instance having old dictionaries
      * @param settingsValues current SettingsValues
      */
-    public void setAdditionalDictionaries(
+    private void resetAdditionalDictionaries(
             final DictionaryFacilitatorForSuggest oldDictionaryFacilitator,
             final SettingsValues settingsValues) {
         // Contacts dictionary
@@ -360,8 +395,12 @@
         return maxFreq;
     }
 
+    private void removeDictionary(final String key) {
+        mDictionaries.remove(key);
+    }
+
     private void addOrReplaceDictionary(final String key, final Dictionary dict) {
-        if (mOnlyDictionarySetForDebug != null && !mOnlyDictionarySetForDebug.contains(key)) {
+        if (mDictionarySubsetForDebug != null && !mDictionarySubsetForDebug.contains(key)) {
             Log.w(TAG, "Ignore add " + key + " dictionary for debug.");
             return;
         }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 901e502..03e92d5 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -96,7 +96,8 @@
  * Input method implementation for Qwerty'ish keyboard.
  */
 public class LatinIME extends InputMethodService implements KeyboardActionListener,
-        SuggestionStripView.Listener, Suggest.SuggestInitializationListener {
+        SuggestionStripView.Listener,
+        DictionaryFacilitatorForSuggest.DictionaryInitializationListener {
     private static final String TAG = LatinIME.class.getSimpleName();
     private static final boolean TRACE = false;
     private static boolean DEBUG = false;
@@ -515,12 +516,17 @@
         // be done later inside {@see #initSuggest()} when the reopenDictionaries message is
         // processed.
         final SettingsValues currentSettingsValues = mSettings.getCurrent();
-        if (!mHandler.hasPendingReopenDictionaries() && mInputLogic.mSuggest != null) {
+        final Suggest suggest = mInputLogic.mSuggest;
+        if (!mHandler.hasPendingReopenDictionaries() && suggest != null) {
             // May need to reset dictionaries depending on the user settings.
-            // TODO: Quit setting dictionaries from LatinIME.
-            mInputLogic.mSuggest.mDictionaryFacilitator.setAdditionalDictionaries(
-                    mInputLogic.mSuggest.mDictionaryFacilitator /* oldDictionaryFacilitator */,
-                    currentSettingsValues);
+            final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
+                    suggest.mDictionaryFacilitator;
+            final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+                    new DictionaryFacilitatorForSuggest(currentSettingsValues,
+                            oldDictionaryFacilitator);
+            // Create Suggest instance with the new dictionary facilitator.
+            mInputLogic.mSuggest = new Suggest(suggest /* oldSuggest */, dictionaryFacilitator);
+            suggest.close();
         }
         if (currentSettingsValues.mUsePersonalizedDicts) {
             PersonalizationDictionarySessionRegistrar.init(this);
@@ -557,19 +563,20 @@
         }
 
         final SettingsValues settingsValues = mSettings.getCurrent();
-        final Suggest newSuggest = new Suggest(this /* Context */, subtypeLocale, settingsValues,
-                this /* SuggestInitializationListener */);
+        final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
+                (mInputLogic.mSuggest == null) ? null : mInputLogic.mSuggest.mDictionaryFacilitator;
+        // Creates new dictionary facilitator for the new locale.
+        final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+                new DictionaryFacilitatorForSuggest(this /* context */, subtypeLocale,
+                        settingsValues, this /* DictionaryInitializationListener */,
+                        oldDictionaryFacilitator);
+        final Suggest newSuggest = new Suggest(subtypeLocale, dictionaryFacilitator);
         if (settingsValues.mCorrectionEnabled) {
             newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold);
         }
-
         if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
             ResearchLogger.getInstance().initDictionary(newSuggest.mDictionaryFacilitator);
         }
-        // TODO: Quit setting dictionaries from LatinIME.
-        newSuggest.mDictionaryFacilitator.setAdditionalDictionaries(
-                (mInputLogic.mSuggest == null) ? null : mInputLogic.mSuggest.mDictionaryFacilitator
-                        /* oldDictionaryFacilitator */, settingsValues);
         final Suggest oldSuggest = mInputLogic.mSuggest;
         mInputLogic.mSuggest = newSuggest;
         if (oldSuggest != null) oldSuggest.close();
@@ -577,7 +584,7 @@
 
     /* package private */ void resetSuggestMainDict() {
         final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
-        mInputLogic.mSuggest.mDictionaryFacilitator.resetMainDict(this, subtypeLocale,
+        mInputLogic.mSuggest.mDictionaryFacilitator.reloadMainDict(this, subtypeLocale,
                 this /* SuggestInitializationListener */);
     }
 
@@ -1940,7 +1947,7 @@
     // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly.
     @UsedForTesting
     /* package for test */ void replaceMainDictionaryForTest(final Locale locale) {
-        mInputLogic.mSuggest.mDictionaryFacilitator.resetMainDict(this, locale, null);
+        mInputLogic.mSuggest.mDictionaryFacilitator.reloadMainDict(this, locale, null);
     }
 
     public void debugDumpStateAndCrashWithException(final String context) {
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 3f38323..5dc8f30 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -16,13 +16,10 @@
 
 package com.android.inputmethod.latin;
 
-import android.content.Context;
 import android.text.TextUtils;
 
-import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.settings.SettingsValues;
 import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
 import com.android.inputmethod.latin.utils.BoundedTreeSet;
 import com.android.inputmethod.latin.utils.CollectionUtils;
@@ -55,10 +52,6 @@
 
     public static final int MAX_SUGGESTIONS = 18;
 
-    public interface SuggestInitializationListener {
-        public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable);
-    }
-
     private static final boolean DBG = LatinImeLogger.sDBG;
 
     public final DictionaryFacilitatorForSuggest mDictionaryFacilitator;
@@ -68,18 +61,18 @@
     // Locale used for upper- and title-casing words
     public final Locale mLocale;
 
-    public Suggest(final Context context, final Locale locale, final SettingsValues settingsValues,
-            final SuggestInitializationListener listener) {
+    public Suggest(final Locale locale,
+            final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
         mLocale = locale;
-        mDictionaryFacilitator = new DictionaryFacilitatorForSuggest(context, locale,
-                settingsValues, listener);
+        mDictionaryFacilitator = dictionaryFacilitator;
     }
 
-    @UsedForTesting
-    Suggest(final Context context, final AssetFileAddress[] dictionaryList, final Locale locale) {
-        mLocale = locale;
-        mDictionaryFacilitator = new DictionaryFacilitatorForSuggest(context, dictionaryList,
-                locale);
+    // Creates instance with new dictionary facilitator.
+    public Suggest(final Suggest oldSuggst,
+            final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
+        mLocale = oldSuggst.mLocale;
+        mAutoCorrectionThreshold = oldSuggst.mAutoCorrectionThreshold;
+        mDictionaryFacilitator = dictionaryFacilitator;
     }
 
     public void setAutoCorrectionThreshold(float threshold) {
diff --git a/java/src/com/android/inputmethod/latin/utils/FileUtils.java b/java/src/com/android/inputmethod/latin/utils/FileUtils.java
index 22b0fbb..f1106a6 100644
--- a/java/src/com/android/inputmethod/latin/utils/FileUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/FileUtils.java
@@ -25,8 +25,11 @@
 public class FileUtils {
     public static boolean deleteRecursively(final File path) {
         if (path.isDirectory()) {
-            for (final File child : path.listFiles()) {
-                deleteRecursively(child);
+            final File[] files = path.listFiles();
+            if (files != null) {
+                for (final File child : files) {
+                    deleteRecursively(child);
+                }
             }
         }
         return path.delete();
@@ -37,6 +40,9 @@
             return false;
         }
         final File[] files = dir.listFiles(fileNameFilter);
+        if (files == null) {
+            return false;
+        }
         boolean hasDeletedAllFiles = true;
         for (final File file : files) {
             if (!deleteRecursively(file)) {