diff --git a/java-overridable/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java b/java-overridable/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java
index df0e3f0e1c67f42da66836f085a3e087b4140e7e..13caea403f5269adee7e58c0898efe4ae7724ffb 100644
--- a/java-overridable/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java
+++ b/java-overridable/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java
@@ -62,4 +62,11 @@ public class DictionaryPackConstants {
      */
     public static final String UPDATE_NOW_INTENT_ACTION = DICTIONARY_DOMAIN
             + ".UPDATE_NOW";
+
+    /**
+     * The intent action to inform the dictionary provider to initialize the db
+     * and update now.
+     */
+    public static final String INIT_AND_UPDATE_NOW_INTENT_ACTION = DICTIONARY_DOMAIN
+            + ".INIT_AND_UPDATE_NOW";
 }
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index 210d9a96429e53a11424fc9ebad81fdb4e6a847a..f58c401c712e1e5d792f4861e059763fad811046 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -144,6 +144,7 @@
                 <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
                 <action android:name="android.intent.action.DATE_CHANGED" />
                 <action android:name="com.android.inputmethod.dictionarypack.aosp.UPDATE_NOW" />
+                <action android:name="com.android.inputmethod.dictionarypack.aosp.INIT_AND_UPDATE_NOW" />
             </intent-filter>
         </receiver>
 
diff --git a/java/res/values/config-dictionary-pack.xml b/java/res/values/config-dictionary-pack.xml
index d076af45229443d30f3a5a9fe4bf2f7e4df6482f..bf52de88bece9f8a51f91ccdce04d5f2cbbdc003 100644
--- a/java/res/values/config-dictionary-pack.xml
+++ b/java/res/values/config-dictionary-pack.xml
@@ -25,6 +25,6 @@
     <bool name="allow_over_roaming">false</bool>
     <bool name="dict_downloads_visible_in_download_UI">false</bool>
     <bool name="metadata_downloads_visible_in_download_UI">false</bool>
-    <bool name="display_notification_for_auto_update">false</bool>
-    <bool name="display_notification_for_user_requested_update">false</bool>
+    <bool name="display_notification_for_auto_update">true</bool>
+    <bool name="display_notification_for_user_requested_update">true</bool>
 </resources>
diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
index 12fdd69b9d1bfdb1983e988bd1f59ba2cb2d3851..ee142d845ca3425391674cbf604bcbbd3d609250 100644
--- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
+++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
@@ -173,7 +173,7 @@ public final class ActionBatch {
             final long downloadId = UpdateHandler.registerDownloadRequest(manager, request, db,
                     mWordList.mId, mWordList.mVersion);
             Log.i(TAG, String.format("Starting the dictionary download with version:"
-                            + " %d and Url: %s" + mWordList.mVersion, uri));
+                            + " %d and Url: %s", mWordList.mVersion, uri));
             DebugLogUtils.l("Starting download of", uri, "with id", downloadId);
             PrivateLog.log("Starting download of " + uri + ", id : " + downloadId);
         }
diff --git a/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java b/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java
index 3d0e29ed084cc171de35f1ea92fb9aea5c5f7965..3cd822a3c961c31a813afbe4ab897ba8acb5b414 100644
--- a/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java
+++ b/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java
@@ -22,6 +22,8 @@ import android.content.SharedPreferences;
 public final class CommonPreferences {
     private static final String COMMON_PREFERENCES_NAME = "LatinImeDictPrefs";
 
+    public static final String PREF_FORCE_DOWNLOAD_DICT = "pref_key_force_download_dict";
+
     public static SharedPreferences getCommonPreferences(final Context context) {
         return context.getSharedPreferences(COMMON_PREFERENCES_NAME, 0);
     }
@@ -37,4 +39,14 @@ public final class CommonPreferences {
         editor.putBoolean(id, false);
         editor.apply();
     }
+
+    public static boolean isForceDownloadDict(Context context) {
+        return getCommonPreferences(context).getBoolean(PREF_FORCE_DOWNLOAD_DICT, false);
+    }
+
+    public static void setForceDownloadDict(Context context, boolean forceDownload) {
+        SharedPreferences.Editor editor = getCommonPreferences(context).edit();
+        editor.putBoolean(PREF_FORCE_DOWNLOAD_DICT, forceDownload);
+        editor.apply();
+    }
 }
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java
index c678f081d89e2a754dcaadb54e5cd1375bfc044a..bbdf2a38083d89363cbcb099c9be0325059e2210 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java
@@ -25,6 +25,7 @@ import android.os.IBinder;
 import android.util.Log;
 import android.widget.Toast;
 
+import com.android.inputmethod.latin.BinaryDictionaryFileDumper;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.common.LocaleUtils;
 
@@ -192,13 +193,26 @@ public final class DictionaryService extends Service {
 
     static void dispatchBroadcast(final Context context, final Intent intent) {
         if (DATE_CHANGED_INTENT_ACTION.equals(intent.getAction())) {
+            // Do not force download dictionaries on date change updates.
+            CommonPreferences.setForceDownloadDict(context, false);
             // This happens when the date of the device changes. This normally happens
             // at midnight local time, but it may happen if the user changes the date
             // by hand or something similar happens.
             checkTimeAndMaybeSetupUpdateAlarm(context);
         } else if (DictionaryPackConstants.UPDATE_NOW_INTENT_ACTION.equals(intent.getAction())) {
             // Intent to trigger an update now.
-            UpdateHandler.tryUpdate(context, false);
+            UpdateHandler.tryUpdate(context, CommonPreferences.isForceDownloadDict(context));
+        } else if (DictionaryPackConstants.INIT_AND_UPDATE_NOW_INTENT_ACTION.equals(
+                intent.getAction())) {
+            // Enable force download of dictionaries irrespective of wifi or metered connection.
+            CommonPreferences.setForceDownloadDict(context, true);
+
+            // Initialize the client Db.
+            final String mClientId = context.getString(R.string.dictionary_pack_client_id);
+            BinaryDictionaryFileDumper.initializeClientRecordHelper(context, mClientId);
+
+            // Updates the metadata and the download the dictionaries.
+            UpdateHandler.tryUpdate(context, true);
         } else {
             UpdateHandler.downloadFinished(context, intent);
         }
@@ -249,7 +263,7 @@ public final class DictionaryService extends Service {
      */
     public static void updateNowIfNotUpdatedInAVeryLongTime(final Context context) {
         if (!isLastUpdateAtLeastThisOld(context, VERY_LONG_TIME_MILLIS)) return;
-        UpdateHandler.tryUpdate(context, false);
+        UpdateHandler.tryUpdate(context, CommonPreferences.isForceDownloadDict(context));
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
index b00a811bb077b2714a5c85a4c4cd2f0d2a2ad062..a2789cc1a38cd61a519eb80b229f467972a8c835 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
@@ -264,6 +264,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
      */
     @Override
     public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
+        // Allow automatic download of dictionaries on upgrading the database.
+        CommonPreferences.setForceDownloadDict(mContext, true);
         if (METADATA_DATABASE_INITIAL_VERSION == oldVersion
                 && METADATA_DATABASE_VERSION_WITH_CLIENTID <= newVersion
                 && CURRENT_METADATA_DATABASE_VERSION >= newVersion) {
diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
index f05db9dabc1f123298bbf28121311c363588c32e..30ff0b8ee39b874800af4fb3b25b2c98bee7a01c 100644
--- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
@@ -449,6 +449,8 @@ public final class UpdateHandler {
         // download, so we are pretty sure it's alive. It's theoretically possible that it's
         // disabled right inbetween the firing of the intent and the control reaching here.
 
+        boolean dictionaryDownloaded = false;
+
         for (final DownloadRecord record : recordList) {
             // downloadSuccessful is not final because we may still have exceptions from now on
             boolean downloadSuccessful = false;
@@ -463,9 +465,15 @@ public final class UpdateHandler {
                     final SQLiteDatabase db = MetadataDbHelper.getDb(context, record.mClientId);
                     publishUpdateWordListCompleted(context, downloadSuccessful, fileId,
                             db, record.mAttributes, record.mClientId);
+                    dictionaryDownloaded = true;
                 }
             }
         }
+
+        if (dictionaryDownloaded) {
+            // Disable the force download after downloading the dictionaries.
+            CommonPreferences.setForceDownloadDict(context, false);
+        }
         // Now that we're done using it, we can remove this download from DLManager
         manager.remove(fileId);
     }
@@ -804,7 +812,7 @@ public final class UpdateHandler {
             } else {
                 final SQLiteDatabase db = MetadataDbHelper.getDb(context, clientId);
                 if (newInfo.mVersion == currentInfo.mVersion) {
-                    if (newInfo.mRemoteFilename == currentInfo.mRemoteFilename) {
+                    if (TextUtils.equals(newInfo.mRemoteFilename, currentInfo.mRemoteFilename)) {
                         // If the dictionary url hasn't changed, we should preserve the retryCount.
                         newInfo.mRetryCount = currentInfo.mRetryCount;
                     }
@@ -820,7 +828,8 @@ public final class UpdateHandler {
                     actions.add(new ActionBatch.MakeAvailableAction(clientId, newInfo));
                     if (status == MetadataDbHelper.STATUS_INSTALLED
                             || status == MetadataDbHelper.STATUS_DISABLED) {
-                        actions.add(new ActionBatch.StartDownloadAction(clientId, newInfo, false));
+                        actions.add(new ActionBatch.StartDownloadAction(
+                                clientId, newInfo, CommonPreferences.isForceDownloadDict(context)));
                     } else {
                         // Pass true to ForgetAction: this is indeed an update to a non-installed
                         // word list, so activate status == AVAILABLE check
@@ -973,8 +982,10 @@ public final class UpdateHandler {
         // change the shared preferences. So there is no way for a word list that has been
         // auto-installed once to get auto-installed again, and that's what we want.
         final ActionBatch actions = new ActionBatch();
-        actions.add(new ActionBatch.StartDownloadAction(clientId,
-                WordListMetadata.createFromContentValues(installCandidate), false));
+        actions.add(new ActionBatch.StartDownloadAction(
+                clientId,
+                WordListMetadata.createFromContentValues(installCandidate),
+                CommonPreferences.isForceDownloadDict(context)));
         final String localeString = installCandidate.getAsString(MetadataDbHelper.LOCALE_COLUMN);
         // We are in a content provider: we can't do any UI at all. We have to defer the displaying
         // itself to the service. Also, we only display this when the user does not have a
@@ -1020,8 +1031,9 @@ public final class UpdateHandler {
                 || MetadataDbHelper.STATUS_DELETING == status) {
             actions.add(new ActionBatch.EnableAction(clientId, wordListMetaData));
         } else if (MetadataDbHelper.STATUS_AVAILABLE == status) {
+            boolean forceDownloadDict = CommonPreferences.isForceDownloadDict(context);
             actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData,
-                    allowDownloadOnMeteredData));
+                    forceDownloadDict || allowDownloadOnMeteredData));
         } else {
             Log.e(TAG, "Unexpected state of the word list for markAsUsed : " + status);
         }
@@ -1133,7 +1145,8 @@ public final class UpdateHandler {
                     context, clientId, wordlistId, version);
 
             final ActionBatch actions = new ActionBatch();
-            actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData, false));
+            actions.add(new ActionBatch.StartDownloadAction(
+                    clientId, wordListMetaData, CommonPreferences.isForceDownloadDict(context)));
             actions.execute(context, new LogProblemReporter(TAG));
         } else {
             if (DEBUG) {
diff --git a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
index 5c3abd2dbdc0da5e9980f752772468ac7be2f62d..2a69d36502deac87db24d41e5cb44d5984b9f0f6 100644
--- a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
+++ b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
@@ -27,6 +27,8 @@ import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.inputmethod.dictionarypack.CommonPreferences;
+import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
 import com.android.inputmethod.keyboard.KeyboardLayoutSet;
 import com.android.inputmethod.latin.setup.SetupActivity;
 import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
@@ -70,6 +72,7 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
             final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes();
             richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
             toggleAppIcon(context);
+            downloadLatestDictionaries(context);
         } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
             Log.i(TAG, "Boot has been completed");
             toggleAppIcon(context);
@@ -97,6 +100,12 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
         }
     }
 
+    private void downloadLatestDictionaries(Context context) {
+        final Intent updateIntent = new Intent(
+                DictionaryPackConstants.INIT_AND_UPDATE_NOW_INTENT_ACTION);
+        context.sendBroadcast(updateIntent);
+    }
+
     private static void toggleAppIcon(final Context context) {
         final int appInfoFlags = context.getApplicationInfo().flags;
         final boolean isSystemApp = (appInfoFlags & ApplicationInfo.FLAG_SYSTEM) > 0;
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index fd567f49d37c7016ce8392b98f05847efac920c4..d8e332370b2f00f40e4e8b91120fc9ea35f1411d 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -22,11 +22,13 @@ import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.AssetFileAddress;
 import com.android.inputmethod.latin.BinaryDictionaryGetter;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
 import com.android.inputmethod.latin.common.LocaleUtils;
 import com.android.inputmethod.latin.define.DecoderSpecificConstants;
 import com.android.inputmethod.latin.makedict.DictionaryHeader;
@@ -37,6 +39,7 @@ import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 
@@ -69,12 +72,11 @@ public class DictionaryInfoUtils {
         public final Locale mLocale;
         @Nullable
         public final String mDescription;
-        @Nonnull
         public final AssetFileAddress mFileAddress;
         public final int mVersion;
 
         public DictionaryInfo(@Nonnull final String id, @Nonnull final Locale locale,
-                @Nullable final String description, @Nonnull final AssetFileAddress fileAddress,
+                @Nullable final String description, @Nullable final AssetFileAddress fileAddress,
                 final int version) {
             mId = id;
             mLocale = locale;
@@ -88,10 +90,12 @@ public class DictionaryInfoUtils {
             values.put(WORDLISTID_COLUMN, mId);
             values.put(LOCALE_COLUMN, mLocale.toString());
             values.put(DESCRIPTION_COLUMN, mDescription);
-            values.put(LOCAL_FILENAME_COLUMN, mFileAddress.mFilename);
+            values.put(LOCAL_FILENAME_COLUMN,
+                    mFileAddress != null ? mFileAddress.mFilename : "");
             values.put(DATE_COLUMN, TimeUnit.MILLISECONDS.toSeconds(
-                    new File(mFileAddress.mFilename).lastModified()));
-            values.put(FILESIZE_COLUMN, mFileAddress.mLength);
+                    mFileAddress != null ? new File(mFileAddress.mFilename).lastModified() : 0));
+            values.put(FILESIZE_COLUMN,
+                    mFileAddress != null ? mFileAddress.mLength : 0);
             values.put(VERSION_COLUMN, mVersion);
             return values;
         }
@@ -360,7 +364,6 @@ public class DictionaryInfoUtils {
      * @param locale Locale for this file.
      * @return information of the specified dictionary.
      */
-    @Nullable
     private static DictionaryInfo createDictionaryInfoFromFileAddress(
             final AssetFileAddress fileAddress, Locale locale) {
         final String id = getMainDictId(locale);
@@ -370,6 +373,17 @@ public class DictionaryInfoUtils {
         return new DictionaryInfo(id, locale, description, fileAddress, version);
     }
 
+    /**
+     * Returns dictionary information for the given locale.
+     */
+    private static DictionaryInfo createDictionaryInfoFromLocale(Locale locale) {
+        final String id = getMainDictId(locale);
+        final int version = -1;
+        final String description = SubtypeLocaleUtils
+                .getSubtypeLocaleDisplayName(locale.toString());
+        return new DictionaryInfo(id, locale, description, null, version);
+    }
+
     private static void addOrUpdateDictInfo(final ArrayList<DictionaryInfo> dictList,
             final DictionaryInfo newElement) {
         final Iterator<DictionaryInfo> iter = dictList.iterator();
@@ -441,6 +455,17 @@ public class DictionaryInfoUtils {
             addOrUpdateDictInfo(dictList, dictionaryInfo);
         }
 
+        // Generate the dictionary information from  the enabled subtypes. This will not
+        // overwrite the real records.
+        RichInputMethodManager.init(context);
+        List<InputMethodSubtype> enabledSubtypes = RichInputMethodManager
+                .getInstance().getMyEnabledInputMethodSubtypeList(true);
+        for (InputMethodSubtype subtype : enabledSubtypes) {
+            Locale locale = LocaleUtils.constructLocaleFromString(subtype.getLocale());
+            DictionaryInfo dictionaryInfo = createDictionaryInfoFromLocale(locale);
+            addOrUpdateDictInfo(dictList, dictionaryInfo);
+        }
+
         return dictList;
     }