diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
index 3d294acd7efcc5ca7b11d7cf8371c524739dfe83..3aa026e776fa82d215b6951beb8cd4bc88bee750 100644
--- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
+++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
@@ -120,9 +120,10 @@ public final class ActionBatch {
             if (MetadataDbHelper.STATUS_DOWNLOADING == status) {
                 // The word list is still downloading. Cancel the download and revert the
                 // word list status to "available".
-                 manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN));
+                manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN));
                 MetadataDbHelper.markEntryAsAvailable(db, mWordList.mId, mWordList.mVersion);
-            } else if (MetadataDbHelper.STATUS_AVAILABLE != status) {
+            } else if (MetadataDbHelper.STATUS_AVAILABLE != status
+                    && MetadataDbHelper.STATUS_RETRYING != status) {
                 // Should never happen
                 Log.e(TAG, "Unexpected state of the word list '" + mWordList.mId + "' : " + status
                         + " for an upgrade action. Fall back to download.");
@@ -325,8 +326,8 @@ public final class ActionBatch {
                     mWordList.mId, mWordList.mLocale, mWordList.mDescription,
                     null == mWordList.mLocalFilename ? "" : mWordList.mLocalFilename,
                     mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum,
-                    mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion,
-                    mWordList.mFormatVersion);
+                    mWordList.mChecksum, mWordList.mRetryCount, mWordList.mFileSize,
+                    mWordList.mVersion, mWordList.mFormatVersion);
             PrivateLog.log("Insert 'available' record for " + mWordList.mDescription
                     + " and locale " + mWordList.mLocale);
             db.insert(MetadataDbHelper.METADATA_TABLE_NAME, null, values);
@@ -374,9 +375,9 @@ public final class ActionBatch {
             final ContentValues values = MetadataDbHelper.makeContentValues(0,
                     MetadataDbHelper.TYPE_BULK, MetadataDbHelper.STATUS_INSTALLED,
                     mWordList.mId, mWordList.mLocale, mWordList.mDescription,
-                    "", mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum,
-                    mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion,
-                    mWordList.mFormatVersion);
+                    "", mWordList.mRemoteFilename, mWordList.mLastUpdate,
+                    mWordList.mRawChecksum, mWordList.mChecksum, mWordList.mRetryCount,
+                    mWordList.mFileSize, mWordList.mVersion, mWordList.mFormatVersion);
             PrivateLog.log("Insert 'preinstalled' record for " + mWordList.mDescription
                     + " and locale " + mWordList.mLocale);
             db.insert(MetadataDbHelper.METADATA_TABLE_NAME, null, values);
@@ -417,8 +418,8 @@ public final class ActionBatch {
                     mWordList.mId, mWordList.mLocale, mWordList.mDescription,
                     oldValues.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN),
                     mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum,
-                    mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion,
-                    mWordList.mFormatVersion);
+                    mWordList.mChecksum, mWordList.mRetryCount, mWordList.mFileSize,
+                    mWordList.mVersion, mWordList.mFormatVersion);
             PrivateLog.log("Updating record for " + mWordList.mDescription
                     + " and locale " + mWordList.mLocale);
             db.update(MetadataDbHelper.METADATA_TABLE_NAME, values,
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
index f5bd84c8c715df4fd98b7f2852937a72e07d0d86..e748321e2725aea9fa39aad38bd54d8782f80200 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
@@ -470,7 +470,11 @@ public final class DictionaryProvider extends ContentProvider {
         } else if (MetadataDbHelper.STATUS_INSTALLED == status) {
             final String result = uri.getQueryParameter(QUERY_PARAMETER_DELETE_RESULT);
             if (QUERY_PARAMETER_FAILURE.equals(result)) {
-                UpdateHandler.markAsBroken(getContext(), clientId, wordlistId, version);
+                if (DEBUG) {
+                    Log.d(TAG,
+                            "Dictionary is broken, attempting to retry download & installation.");
+                }
+                UpdateHandler.markAsBrokenOrRetrying(getContext(), clientId, wordlistId, version);
             }
             final String localFilename =
                     wordList.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN);
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
index 17dd781d55813015d3992e8a911d51e9d873c9ae..e9dde4245eac5ec7557bbdfa57aa104b72d7f2df 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
@@ -47,10 +47,13 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
     // used to identify the versions for upgrades. This should never change going forward.
     private static final int METADATA_DATABASE_VERSION_WITH_CLIENTID = 6;
     // The current database version.
-    private static final int CURRENT_METADATA_DATABASE_VERSION = 9;
+    private static final int CURRENT_METADATA_DATABASE_VERSION = 10;
 
     private final static long NOT_A_DOWNLOAD_ID = -1;
 
+    // The number of retries allowed when attempting to download a broken dictionary.
+    public static final int DICTIONARY_RETRY_THRESHOLD = 2;
+
     public static final String METADATA_TABLE_NAME = "pendingUpdates";
     static final String CLIENT_TABLE_NAME = "clients";
     public static final String PENDINGID_COLUMN = "pendingid"; // Download Manager ID
@@ -68,7 +71,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
     public static final String FORMATVERSION_COLUMN = "formatversion";
     public static final String FLAGS_COLUMN = "flags";
     public static final String RAW_CHECKSUM_COLUMN = "rawChecksum";
-    public static final int COLUMN_COUNT = 14;
+    public static final String RETRY_COUNT_COLUMN = "remainingRetries";
+    public static final int COLUMN_COUNT = 15;
 
     private static final String CLIENT_CLIENT_ID_COLUMN = "clientid";
     private static final String CLIENT_METADATA_URI_COLUMN = "uri";
@@ -98,6 +102,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
     // Deleting: the user marked this word list to be deleted, but it has not been yet because
     // Latin IME is not up yet.
     public static final int STATUS_DELETING = 5;
+    // Retry: dictionary got corrupted, so an attempt must be done to download & install it again.
+    public static final int STATUS_RETRYING = 6;
 
     // Types, for storing in the TYPE_COLUMN
     // This is metadata about what is available.
@@ -124,6 +130,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
             + FORMATVERSION_COLUMN + " INTEGER, "
             + FLAGS_COLUMN + " INTEGER, "
             + RAW_CHECKSUM_COLUMN + " TEXT,"
+            + RETRY_COUNT_COLUMN + " INTEGER, "
             + "PRIMARY KEY (" + WORDLISTID_COLUMN + "," + VERSION_COLUMN + "));";
     private static final String METADATA_CREATE_CLIENT_TABLE =
             "CREATE TABLE IF NOT EXISTS " + CLIENT_TABLE_NAME + " ("
@@ -140,7 +147,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
             STATUS_COLUMN, WORDLISTID_COLUMN, LOCALE_COLUMN, DESCRIPTION_COLUMN,
             LOCAL_FILENAME_COLUMN, REMOTE_FILENAME_COLUMN, DATE_COLUMN, CHECKSUM_COLUMN,
             FILESIZE_COLUMN, VERSION_COLUMN, FORMATVERSION_COLUMN, FLAGS_COLUMN,
-            RAW_CHECKSUM_COLUMN };
+            RAW_CHECKSUM_COLUMN, RETRY_COUNT_COLUMN };
     // List of all client table columns.
     static final String[] CLIENT_TABLE_COLUMNS = { CLIENT_CLIENT_ID_COLUMN,
             CLIENT_METADATA_URI_COLUMN, CLIENT_PENDINGID_COLUMN, FLAGS_COLUMN };
@@ -219,7 +226,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
         createClientTable(db);
     }
 
-    private void addRawChecksumColumnUnlessPresent(final SQLiteDatabase db, final String clientId) {
+    private void addRawChecksumColumnUnlessPresent(final SQLiteDatabase db) {
         try {
             db.execSQL("SELECT " + RAW_CHECKSUM_COLUMN + " FROM "
                     + METADATA_TABLE_NAME + " LIMIT 0;");
@@ -230,6 +237,17 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
         }
     }
 
+    private void addRetryCountColumnUnlessPresent(final SQLiteDatabase db) {
+        try {
+            db.execSQL("SELECT " + RETRY_COUNT_COLUMN + " FROM "
+                    + METADATA_TABLE_NAME + " LIMIT 0;");
+        } catch (SQLiteException e) {
+            Log.i(TAG, "No " + RETRY_COUNT_COLUMN + " column : creating it");
+            db.execSQL("ALTER TABLE " + METADATA_TABLE_NAME + " ADD COLUMN "
+                    + RETRY_COUNT_COLUMN + " INTEGER DEFAULT " + DICTIONARY_RETRY_THRESHOLD + ";");
+        }
+    }
+
     /**
      * Upgrade the database. Upgrade from version 3 is supported.
      * Version 3 has a DB named METADATA_DATABASE_NAME_STEM containing a table METADATA_TABLE_NAME.
@@ -280,7 +298,14 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
         // strengthen the system against corrupted dictionary files.
         // The most secure way to upgrade a database is to just test for the column presence, and
         // add it if it's not there.
-        addRawChecksumColumnUnlessPresent(db, mClientId);
+        addRawChecksumColumnUnlessPresent(db);
+
+        // A retry count column that did not exist in the previous versions was added that
+        // corresponds to the number of download & installation attempts that have been made
+        // in order to strengthen the system recovery from corrupted dictionary files.
+        // The most secure way to upgrade a database is to just test for the column presence, and
+        // add it if it's not there.
+        addRetryCountColumnUnlessPresent(db);
     }
 
     /**
@@ -452,8 +477,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
     public static ContentValues makeContentValues(final int pendingId, final int type,
             final int status, final String wordlistId, final String locale,
             final String description, final String filename, final String url, final long date,
-            final String rawChecksum, final String checksum, final long filesize, final int version,
-            final int formatVersion) {
+            final String rawChecksum, final String checksum, final int retryCount,
+            final long filesize, final int version, final int formatVersion) {
         final ContentValues result = new ContentValues(COLUMN_COUNT);
         result.put(PENDINGID_COLUMN, pendingId);
         result.put(TYPE_COLUMN, type);
@@ -465,6 +490,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
         result.put(REMOTE_FILENAME_COLUMN, url);
         result.put(DATE_COLUMN, date);
         result.put(RAW_CHECKSUM_COLUMN, rawChecksum);
+        result.put(RETRY_COUNT_COLUMN, retryCount);
         result.put(CHECKSUM_COLUMN, checksum);
         result.put(FILESIZE_COLUMN, filesize);
         result.put(VERSION_COLUMN, version);
@@ -502,6 +528,9 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
         if (null == result.get(DATE_COLUMN)) result.put(DATE_COLUMN, 0);
         // Raw checksum unknown unless specified
         if (null == result.get(RAW_CHECKSUM_COLUMN)) result.put(RAW_CHECKSUM_COLUMN, "");
+        // Retry column 0 unless specified
+        if (null == result.get(RETRY_COUNT_COLUMN)) result.put(RETRY_COUNT_COLUMN,
+                DICTIONARY_RETRY_THRESHOLD);
         // Checksum unknown unless specified
         if (null == result.get(CHECKSUM_COLUMN)) result.put(CHECKSUM_COLUMN, "");
         // No filesize unless specified
@@ -551,6 +580,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
             putIntResult(result, cursor, DATE_COLUMN);
             putStringResult(result, cursor, RAW_CHECKSUM_COLUMN);
             putStringResult(result, cursor, CHECKSUM_COLUMN);
+            putIntResult(result, cursor, RETRY_COUNT_COLUMN);
             putIntResult(result, cursor, FILESIZE_COLUMN);
             putIntResult(result, cursor, VERSION_COLUMN);
             putIntResult(result, cursor, FORMATVERSION_COLUMN);
@@ -676,8 +706,16 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
             final String id, final int version) {
         final Cursor cursor = db.query(METADATA_TABLE_NAME,
                 METADATA_TABLE_COLUMNS,
-                WORDLISTID_COLUMN + "= ? AND " + VERSION_COLUMN + "= ?",
-                new String[] { id, Integer.toString(version) }, null, null, null);
+                WORDLISTID_COLUMN + "= ? AND " + VERSION_COLUMN + "= ? AND "
+                        + FORMATVERSION_COLUMN + "<= ?",
+                new String[]
+                        { id,
+                          Integer.toString(version),
+                          Integer.toString(UpdateHandler.MAXIMUM_SUPPORTED_FORMAT_VERSION)
+                        },
+                null /* groupBy */,
+                null /* having */,
+                FORMATVERSION_COLUMN + " DESC"/* orderBy */);
         if (null == cursor) {
             return null;
         }
@@ -706,7 +744,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
             return null;
         }
         try {
-            // This is a lookup by primary key, so there can't be more than one result.
+            // Return the first result from the list of results.
             return getFirstLineAsContentValues(cursor);
         } finally {
             cursor.close();
@@ -1085,4 +1123,27 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
             final int version) {
         markEntryAs(db, id, version, STATUS_DELETING, NOT_A_DOWNLOAD_ID);
     }
+
+    /**
+     * Checks retry counts and marks the word list as retrying if retry is possible.
+     *
+     * @param db the metadata database.
+     * @param id the id of the word list.
+     * @param version the version of the word list.
+     * @return {@code true} if the retry is possible.
+     */
+    public static boolean maybeMarkEntryAsRetrying(final SQLiteDatabase db, final String id,
+            final int version) {
+        final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db, id, version);
+        int retryCount = values.getAsInteger(MetadataDbHelper.RETRY_COUNT_COLUMN);
+        if (retryCount > 1) {
+            values.put(STATUS_COLUMN, STATUS_RETRYING);
+            values.put(RETRY_COUNT_COLUMN, retryCount - 1);
+            db.update(METADATA_TABLE_NAME, values,
+                    WORDLISTID_COLUMN + " = ? AND " + VERSION_COLUMN + " = ?",
+                    new String[] { id, Integer.toString(version) });
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java b/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java
index d66b6905042f0ee6b2b25c32bd772c31fd4a5193..639d904a08f6f079b11d1c08573b87b165acdfd6 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.dictionarypack;
 
+import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 
@@ -55,6 +56,7 @@ public class MetadataHandler {
             final int rawChecksumIndex =
                     results.getColumnIndex(MetadataDbHelper.RAW_CHECKSUM_COLUMN);
             final int checksumIndex = results.getColumnIndex(MetadataDbHelper.CHECKSUM_COLUMN);
+            final int retryCountIndex = results.getColumnIndex(MetadataDbHelper.RETRY_COUNT_COLUMN);
             final int localFilenameIndex =
                     results.getColumnIndex(MetadataDbHelper.LOCAL_FILENAME_COLUMN);
             final int remoteFilenameIndex =
@@ -70,6 +72,7 @@ public class MetadataHandler {
                         results.getLong(fileSizeIndex),
                         results.getString(rawChecksumIndex),
                         results.getString(checksumIndex),
+                        results.getInt(retryCountIndex),
                         results.getString(localFilenameIndex),
                         results.getString(remoteFilenameIndex),
                         results.getInt(versionIndex),
@@ -101,6 +104,22 @@ public class MetadataHandler {
         }
     }
 
+    /**
+     * Gets the metadata, for a specific dictionary.
+     *
+     * @param context The context to open files over.
+     * @param clientId the client id for retrieving the database. null for default (deprecated).
+     * @param wordListId the word list ID.
+     * @param version the word list version.
+     * @return the current metaData
+     */
+    public static WordListMetadata getCurrentMetadataForWordList(final Context context,
+            final String clientId, final String wordListId, final int version) {
+        final ContentValues contentValues = MetadataDbHelper.getContentValuesByWordListId(
+                MetadataDbHelper.getDb(context, clientId), wordListId, version);
+        return WordListMetadata.createFromContentValues(contentValues);
+    }
+
     /**
      * Read metadata from a stream.
      * @param input The stream to read from.
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataParser.java b/java/src/com/android/inputmethod/dictionarypack/MetadataParser.java
index 52290cadce8020b0e6dac6db16e2c0298e17d3e8..2b67ae9ffde8d7738787a330ecbe95a1c73a684a 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataParser.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataParser.java
@@ -83,6 +83,7 @@ public class MetadataParser {
                 Long.parseLong(arguments.get(FILESIZE_FIELD_NAME)),
                 arguments.get(RAW_CHECKSUM_FIELD_NAME),
                 arguments.get(CHECKSUM_FIELD_NAME),
+                MetadataDbHelper.DICTIONARY_RETRY_THRESHOLD /* retryCount */,
                 null,
                 arguments.get(REMOTE_FILENAME_FIELD_NAME),
                 Integer.parseInt(arguments.get(VERSION_FIELD_NAME)),
diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
index 6fbca44c52e5693e49fb21bdc637bee658d04e26..d8c5f31653e9da503a254df6850a2ebdf4620ac6 100644
--- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
@@ -31,7 +31,6 @@ import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.ConnectivityManager;
 import android.net.Uri;
-import android.os.Build;
 import android.os.ParcelFileDescriptor;
 import android.text.TextUtils;
 import android.util.Log;
@@ -785,6 +784,10 @@ public final class UpdateHandler {
             } else {
                 final SQLiteDatabase db = MetadataDbHelper.getDb(context, clientId);
                 if (newInfo.mVersion == currentInfo.mVersion) {
+                    if (newInfo.mRemoteFilename == currentInfo.mRemoteFilename) {
+                        // If the dictionary url hasn't changed, we should preserve the retryCount.
+                        newInfo.mRetryCount = currentInfo.mRetryCount;
+                    }
                     // If it's the same id/version, we update the DB with the new values.
                     // It doesn't matter too much if they didn't change.
                     actions.add(new ActionBatch.UpdateDataAction(clientId, newInfo));
@@ -987,16 +990,17 @@ public final class UpdateHandler {
     public static void markAsUsed(final Context context, final String clientId,
             final String wordlistId, final int version,
             final int status, final boolean allowDownloadOnMeteredData) {
-        final List<WordListMetadata> currentMetadata =
-                MetadataHandler.getCurrentMetadata(context, clientId);
-        WordListMetadata wordList = MetadataHandler.findWordListById(currentMetadata, wordlistId);
-        if (null == wordList) return;
+        final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+                context, clientId, wordlistId, version);
+
+        if (null == wordListMetaData) return;
+
         final ActionBatch actions = new ActionBatch();
         if (MetadataDbHelper.STATUS_DISABLED == status
                 || MetadataDbHelper.STATUS_DELETING == status) {
-            actions.add(new ActionBatch.EnableAction(clientId, wordList));
+            actions.add(new ActionBatch.EnableAction(clientId, wordListMetaData));
         } else if (MetadataDbHelper.STATUS_AVAILABLE == status) {
-            actions.add(new ActionBatch.StartDownloadAction(clientId, wordList,
+            actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData,
                     allowDownloadOnMeteredData));
         } else {
             Log.e(TAG, "Unexpected state of the word list for markAsUsed : " + status);
@@ -1022,13 +1026,13 @@ public final class UpdateHandler {
     // markAsUsed for consistency.
     public static void markAsUnused(final Context context, final String clientId,
             final String wordlistId, final int version, final int status) {
-        final List<WordListMetadata> currentMetadata =
-                MetadataHandler.getCurrentMetadata(context, clientId);
-        final WordListMetadata wordList =
-                MetadataHandler.findWordListById(currentMetadata, wordlistId);
-        if (null == wordList) return;
+
+        final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+                context, clientId, wordlistId, version);
+
+        if (null == wordListMetaData) return;
         final ActionBatch actions = new ActionBatch();
-        actions.add(new ActionBatch.DisableAction(clientId, wordList));
+        actions.add(new ActionBatch.DisableAction(clientId, wordListMetaData));
         actions.execute(context, new LogProblemReporter(TAG));
         signalNewDictionaryState(context);
     }
@@ -1051,14 +1055,14 @@ public final class UpdateHandler {
      */
     public static void markAsDeleting(final Context context, final String clientId,
             final String wordlistId, final int version, final int status) {
-        final List<WordListMetadata> currentMetadata =
-                MetadataHandler.getCurrentMetadata(context, clientId);
-        final WordListMetadata wordList =
-                MetadataHandler.findWordListById(currentMetadata, wordlistId);
-        if (null == wordList) return;
+
+        final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+                context, clientId, wordlistId, version);
+
+        if (null == wordListMetaData) return;
         final ActionBatch actions = new ActionBatch();
-        actions.add(new ActionBatch.DisableAction(clientId, wordList));
-        actions.add(new ActionBatch.StartDeleteAction(clientId, wordList));
+        actions.add(new ActionBatch.DisableAction(clientId, wordListMetaData));
+        actions.add(new ActionBatch.StartDeleteAction(clientId, wordListMetaData));
         actions.execute(context, new LogProblemReporter(TAG));
         signalNewDictionaryState(context);
     }
@@ -1076,33 +1080,47 @@ public final class UpdateHandler {
      */
     public static void markAsDeleted(final Context context, final String clientId,
             final String wordlistId, final int version, final int status) {
-        final List<WordListMetadata> currentMetadata =
-                MetadataHandler.getCurrentMetadata(context, clientId);
-        final WordListMetadata wordList =
-                MetadataHandler.findWordListById(currentMetadata, wordlistId);
-        if (null == wordList) return;
+        final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+                        context, clientId, wordlistId, version);
+
+        if (null == wordListMetaData) return;
+
         final ActionBatch actions = new ActionBatch();
-        actions.add(new ActionBatch.FinishDeleteAction(clientId, wordList));
+        actions.add(new ActionBatch.FinishDeleteAction(clientId, wordListMetaData));
         actions.execute(context, new LogProblemReporter(TAG));
         signalNewDictionaryState(context);
     }
 
     /**
-     * Marks the word list with the passed id as broken.
-     *
-     * This effectively deletes the entry from the metadata. It doesn't prevent the same
-     * word list to be downloaded again at a later time if the same or a new version is
-     * available the next time we download the metadata.
+     * Checks whether the word list should be downloaded again; in which case an download &
+     * installation attempt is made. Otherwise the word list is marked broken.
      *
      * @param context the context to open the database on.
      * @param clientId the id of the client.
-     * @param wordlistId the id of the word list to mark as broken.
-     * @param version the version of the word list to mark as deleted.
+     * @param wordlistId the id of the word list which is broken.
+     * @param version the version of the broken word list.
      */
-    public static void markAsBroken(final Context context, final String clientId,
+    public static void markAsBrokenOrRetrying(final Context context, final String clientId,
             final String wordlistId, final int version) {
-        // TODO: do this on another thread to avoid blocking the UI.
-        MetadataDbHelper.deleteEntry(MetadataDbHelper.getDb(context, clientId),
-                wordlistId, version);
+        boolean isRetryPossible = MetadataDbHelper.maybeMarkEntryAsRetrying(
+                MetadataDbHelper.getDb(context, clientId), wordlistId, version);
+
+        if (isRetryPossible) {
+            if (DEBUG) {
+                Log.d(TAG, "Attempting to download & install the wordlist again.");
+            }
+            final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
+                    context, clientId, wordlistId, version);
+
+            final ActionBatch actions = new ActionBatch();
+            actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData, false));
+            actions.execute(context, new LogProblemReporter(TAG));
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "Retries for wordlist exhausted, deleting the wordlist from table.");
+            }
+            MetadataDbHelper.deleteEntry(MetadataDbHelper.getDb(context, clientId),
+                    wordlistId, version);
+        }
     }
 }
diff --git a/java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java b/java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java
index 9e510a68bf2c3a8e4a556bd7251c8ce840f01b3f..59f75e4edb7094cad82e7a2b2b0c70d5e16d7b2a 100644
--- a/java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java
+++ b/java/src/com/android/inputmethod/dictionarypack/WordListMetadata.java
@@ -36,6 +36,7 @@ public class WordListMetadata {
     public final String mRemoteFilename;
     public final int mVersion; // version of this word list
     public final int mFlags; // Always 0 in this version, reserved for future use
+    public int mRetryCount;
 
     // The locale is matched against the locale requested by the client. The matching algorithm
     // is a standard locale matching with fallback; it is implemented in
@@ -51,8 +52,9 @@ public class WordListMetadata {
 
     public WordListMetadata(final String id, final int type,
             final String description, final long lastUpdate, final long fileSize,
-            final String rawChecksum, final String checksum, final String localFilename,
-            final String remoteFilename, final int version, final int formatVersion,
+            final String rawChecksum, final String checksum, final int retryCount,
+            final String localFilename, final String remoteFilename,
+            final int version, final int formatVersion,
             final int flags, final String locale) {
         mId = id;
         mType = type;
@@ -61,6 +63,7 @@ public class WordListMetadata {
         mFileSize = fileSize;
         mRawChecksum = rawChecksum;
         mChecksum = checksum;
+        mRetryCount = retryCount;
         mLocalFilename = localFilename;
         mRemoteFilename = remoteFilename;
         mVersion = version;
@@ -82,6 +85,7 @@ public class WordListMetadata {
         final Long fileSize = values.getAsLong(MetadataDbHelper.FILESIZE_COLUMN);
         final String rawChecksum = values.getAsString(MetadataDbHelper.RAW_CHECKSUM_COLUMN);
         final String checksum = values.getAsString(MetadataDbHelper.CHECKSUM_COLUMN);
+        final int retryCount = values.getAsInteger(MetadataDbHelper.RETRY_COUNT_COLUMN);
         final String localFilename = values.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN);
         final String remoteFilename = values.getAsString(MetadataDbHelper.REMOTE_FILENAME_COLUMN);
         final Integer version = values.getAsInteger(MetadataDbHelper.VERSION_COLUMN);
@@ -103,7 +107,8 @@ public class WordListMetadata {
             throw new IllegalArgumentException();
         }
         return new WordListMetadata(id, type, description, lastUpdate, fileSize, rawChecksum,
-                checksum, localFilename, remoteFilename, version, formatVersion, flags, locale);
+                checksum, retryCount, localFilename, remoteFilename, version, formatVersion,
+                flags, locale);
     }
 
     @Override
@@ -116,6 +121,7 @@ public class WordListMetadata {
         sb.append("\nFileSize : ").append(mFileSize);
         sb.append("\nRawChecksum : ").append(mRawChecksum);
         sb.append("\nChecksum : ").append(mChecksum);
+        sb.append("\nRetryCount: ").append(mRetryCount);
         sb.append("\nLocalFilename : ").append(mLocalFilename);
         sb.append("\nRemoteFilename : ").append(mRemoteFilename);
         sb.append("\nVersion : ").append(mVersion);