Attempt retry for broken dictionaries

1. Add retry count column within metadata in dictionary pack.
2. Attempt a retry for download and installation by running StartDownloadAction.
3. If the number retrial are at the threshold, we don't attempt it again.

Bug: 15150487
Change-Id: I70720353e5803fccf4728c2aa798883ba75c61e5
main
Jatin Matani 2014-09-02 11:51:25 +09:00
parent 962c40d326
commit 256b1b2a1e
7 changed files with 170 additions and 60 deletions

View File

@ -122,7 +122,8 @@ public final class ActionBatch {
// word list status to "available". // 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); 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 // Should never happen
Log.e(TAG, "Unexpected state of the word list '" + mWordList.mId + "' : " + status Log.e(TAG, "Unexpected state of the word list '" + mWordList.mId + "' : " + status
+ " for an upgrade action. Fall back to download."); + " for an upgrade action. Fall back to download.");
@ -325,8 +326,8 @@ public final class ActionBatch {
mWordList.mId, mWordList.mLocale, mWordList.mDescription, mWordList.mId, mWordList.mLocale, mWordList.mDescription,
null == mWordList.mLocalFilename ? "" : mWordList.mLocalFilename, null == mWordList.mLocalFilename ? "" : mWordList.mLocalFilename,
mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum, mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum,
mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion, mWordList.mChecksum, mWordList.mRetryCount, mWordList.mFileSize,
mWordList.mFormatVersion); mWordList.mVersion, mWordList.mFormatVersion);
PrivateLog.log("Insert 'available' record for " + mWordList.mDescription PrivateLog.log("Insert 'available' record for " + mWordList.mDescription
+ " and locale " + mWordList.mLocale); + " and locale " + mWordList.mLocale);
db.insert(MetadataDbHelper.METADATA_TABLE_NAME, null, values); db.insert(MetadataDbHelper.METADATA_TABLE_NAME, null, values);
@ -374,9 +375,9 @@ public final class ActionBatch {
final ContentValues values = MetadataDbHelper.makeContentValues(0, final ContentValues values = MetadataDbHelper.makeContentValues(0,
MetadataDbHelper.TYPE_BULK, MetadataDbHelper.STATUS_INSTALLED, MetadataDbHelper.TYPE_BULK, MetadataDbHelper.STATUS_INSTALLED,
mWordList.mId, mWordList.mLocale, mWordList.mDescription, mWordList.mId, mWordList.mLocale, mWordList.mDescription,
"", mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum, "", mWordList.mRemoteFilename, mWordList.mLastUpdate,
mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion, mWordList.mRawChecksum, mWordList.mChecksum, mWordList.mRetryCount,
mWordList.mFormatVersion); mWordList.mFileSize, mWordList.mVersion, mWordList.mFormatVersion);
PrivateLog.log("Insert 'preinstalled' record for " + mWordList.mDescription PrivateLog.log("Insert 'preinstalled' record for " + mWordList.mDescription
+ " and locale " + mWordList.mLocale); + " and locale " + mWordList.mLocale);
db.insert(MetadataDbHelper.METADATA_TABLE_NAME, null, values); db.insert(MetadataDbHelper.METADATA_TABLE_NAME, null, values);
@ -417,8 +418,8 @@ public final class ActionBatch {
mWordList.mId, mWordList.mLocale, mWordList.mDescription, mWordList.mId, mWordList.mLocale, mWordList.mDescription,
oldValues.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN), oldValues.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN),
mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum, mWordList.mRemoteFilename, mWordList.mLastUpdate, mWordList.mRawChecksum,
mWordList.mChecksum, mWordList.mFileSize, mWordList.mVersion, mWordList.mChecksum, mWordList.mRetryCount, mWordList.mFileSize,
mWordList.mFormatVersion); mWordList.mVersion, mWordList.mFormatVersion);
PrivateLog.log("Updating record for " + mWordList.mDescription PrivateLog.log("Updating record for " + mWordList.mDescription
+ " and locale " + mWordList.mLocale); + " and locale " + mWordList.mLocale);
db.update(MetadataDbHelper.METADATA_TABLE_NAME, values, db.update(MetadataDbHelper.METADATA_TABLE_NAME, values,

View File

@ -470,7 +470,11 @@ public final class DictionaryProvider extends ContentProvider {
} else if (MetadataDbHelper.STATUS_INSTALLED == status) { } else if (MetadataDbHelper.STATUS_INSTALLED == status) {
final String result = uri.getQueryParameter(QUERY_PARAMETER_DELETE_RESULT); final String result = uri.getQueryParameter(QUERY_PARAMETER_DELETE_RESULT);
if (QUERY_PARAMETER_FAILURE.equals(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 = final String localFilename =
wordList.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN); wordList.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN);

View File

@ -47,10 +47,13 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
// used to identify the versions for upgrades. This should never change going forward. // used to identify the versions for upgrades. This should never change going forward.
private static final int METADATA_DATABASE_VERSION_WITH_CLIENTID = 6; private static final int METADATA_DATABASE_VERSION_WITH_CLIENTID = 6;
// The current database version. // 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; 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"; public static final String METADATA_TABLE_NAME = "pendingUpdates";
static final String CLIENT_TABLE_NAME = "clients"; static final String CLIENT_TABLE_NAME = "clients";
public static final String PENDINGID_COLUMN = "pendingid"; // Download Manager ID 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 FORMATVERSION_COLUMN = "formatversion";
public static final String FLAGS_COLUMN = "flags"; public static final String FLAGS_COLUMN = "flags";
public static final String RAW_CHECKSUM_COLUMN = "rawChecksum"; 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_CLIENT_ID_COLUMN = "clientid";
private static final String CLIENT_METADATA_URI_COLUMN = "uri"; 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 // Deleting: the user marked this word list to be deleted, but it has not been yet because
// Latin IME is not up yet. // Latin IME is not up yet.
public static final int STATUS_DELETING = 5; 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 // Types, for storing in the TYPE_COLUMN
// This is metadata about what is available. // This is metadata about what is available.
@ -124,6 +130,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
+ FORMATVERSION_COLUMN + " INTEGER, " + FORMATVERSION_COLUMN + " INTEGER, "
+ FLAGS_COLUMN + " INTEGER, " + FLAGS_COLUMN + " INTEGER, "
+ RAW_CHECKSUM_COLUMN + " TEXT," + RAW_CHECKSUM_COLUMN + " TEXT,"
+ RETRY_COUNT_COLUMN + " INTEGER, "
+ "PRIMARY KEY (" + WORDLISTID_COLUMN + "," + VERSION_COLUMN + "));"; + "PRIMARY KEY (" + WORDLISTID_COLUMN + "," + VERSION_COLUMN + "));";
private static final String METADATA_CREATE_CLIENT_TABLE = private static final String METADATA_CREATE_CLIENT_TABLE =
"CREATE TABLE IF NOT EXISTS " + CLIENT_TABLE_NAME + " (" "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, STATUS_COLUMN, WORDLISTID_COLUMN, LOCALE_COLUMN, DESCRIPTION_COLUMN,
LOCAL_FILENAME_COLUMN, REMOTE_FILENAME_COLUMN, DATE_COLUMN, CHECKSUM_COLUMN, LOCAL_FILENAME_COLUMN, REMOTE_FILENAME_COLUMN, DATE_COLUMN, CHECKSUM_COLUMN,
FILESIZE_COLUMN, VERSION_COLUMN, FORMATVERSION_COLUMN, FLAGS_COLUMN, FILESIZE_COLUMN, VERSION_COLUMN, FORMATVERSION_COLUMN, FLAGS_COLUMN,
RAW_CHECKSUM_COLUMN }; RAW_CHECKSUM_COLUMN, RETRY_COUNT_COLUMN };
// List of all client table columns. // List of all client table columns.
static final String[] CLIENT_TABLE_COLUMNS = { CLIENT_CLIENT_ID_COLUMN, static final String[] CLIENT_TABLE_COLUMNS = { CLIENT_CLIENT_ID_COLUMN,
CLIENT_METADATA_URI_COLUMN, CLIENT_PENDINGID_COLUMN, FLAGS_COLUMN }; CLIENT_METADATA_URI_COLUMN, CLIENT_PENDINGID_COLUMN, FLAGS_COLUMN };
@ -219,7 +226,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
createClientTable(db); createClientTable(db);
} }
private void addRawChecksumColumnUnlessPresent(final SQLiteDatabase db, final String clientId) { private void addRawChecksumColumnUnlessPresent(final SQLiteDatabase db) {
try { try {
db.execSQL("SELECT " + RAW_CHECKSUM_COLUMN + " FROM " db.execSQL("SELECT " + RAW_CHECKSUM_COLUMN + " FROM "
+ METADATA_TABLE_NAME + " LIMIT 0;"); + 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. * 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. * 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. // strengthen the system against corrupted dictionary files.
// The most secure way to upgrade a database is to just test for the column presence, and // The most secure way to upgrade a database is to just test for the column presence, and
// add it if it's not there. // 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, public static ContentValues makeContentValues(final int pendingId, final int type,
final int status, final String wordlistId, final String locale, final int status, final String wordlistId, final String locale,
final String description, final String filename, final String url, final long date, 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 String rawChecksum, final String checksum, final int retryCount,
final int formatVersion) { final long filesize, final int version, final int formatVersion) {
final ContentValues result = new ContentValues(COLUMN_COUNT); final ContentValues result = new ContentValues(COLUMN_COUNT);
result.put(PENDINGID_COLUMN, pendingId); result.put(PENDINGID_COLUMN, pendingId);
result.put(TYPE_COLUMN, type); result.put(TYPE_COLUMN, type);
@ -465,6 +490,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
result.put(REMOTE_FILENAME_COLUMN, url); result.put(REMOTE_FILENAME_COLUMN, url);
result.put(DATE_COLUMN, date); result.put(DATE_COLUMN, date);
result.put(RAW_CHECKSUM_COLUMN, rawChecksum); result.put(RAW_CHECKSUM_COLUMN, rawChecksum);
result.put(RETRY_COUNT_COLUMN, retryCount);
result.put(CHECKSUM_COLUMN, checksum); result.put(CHECKSUM_COLUMN, checksum);
result.put(FILESIZE_COLUMN, filesize); result.put(FILESIZE_COLUMN, filesize);
result.put(VERSION_COLUMN, version); 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); if (null == result.get(DATE_COLUMN)) result.put(DATE_COLUMN, 0);
// Raw checksum unknown unless specified // Raw checksum unknown unless specified
if (null == result.get(RAW_CHECKSUM_COLUMN)) result.put(RAW_CHECKSUM_COLUMN, ""); 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 // Checksum unknown unless specified
if (null == result.get(CHECKSUM_COLUMN)) result.put(CHECKSUM_COLUMN, ""); if (null == result.get(CHECKSUM_COLUMN)) result.put(CHECKSUM_COLUMN, "");
// No filesize unless specified // No filesize unless specified
@ -551,6 +580,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
putIntResult(result, cursor, DATE_COLUMN); putIntResult(result, cursor, DATE_COLUMN);
putStringResult(result, cursor, RAW_CHECKSUM_COLUMN); putStringResult(result, cursor, RAW_CHECKSUM_COLUMN);
putStringResult(result, cursor, CHECKSUM_COLUMN); putStringResult(result, cursor, CHECKSUM_COLUMN);
putIntResult(result, cursor, RETRY_COUNT_COLUMN);
putIntResult(result, cursor, FILESIZE_COLUMN); putIntResult(result, cursor, FILESIZE_COLUMN);
putIntResult(result, cursor, VERSION_COLUMN); putIntResult(result, cursor, VERSION_COLUMN);
putIntResult(result, cursor, FORMATVERSION_COLUMN); putIntResult(result, cursor, FORMATVERSION_COLUMN);
@ -676,8 +706,16 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
final String id, final int version) { final String id, final int version) {
final Cursor cursor = db.query(METADATA_TABLE_NAME, final Cursor cursor = db.query(METADATA_TABLE_NAME,
METADATA_TABLE_COLUMNS, METADATA_TABLE_COLUMNS,
WORDLISTID_COLUMN + "= ? AND " + VERSION_COLUMN + "= ?", WORDLISTID_COLUMN + "= ? AND " + VERSION_COLUMN + "= ? AND "
new String[] { id, Integer.toString(version) }, null, null, null); + 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) { if (null == cursor) {
return null; return null;
} }
@ -706,7 +744,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
return null; return null;
} }
try { 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); return getFirstLineAsContentValues(cursor);
} finally { } finally {
cursor.close(); cursor.close();
@ -1085,4 +1123,27 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
final int version) { final int version) {
markEntryAs(db, id, version, STATUS_DELETING, NOT_A_DOWNLOAD_ID); 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;
}
} }

View File

@ -16,6 +16,7 @@
package com.android.inputmethod.dictionarypack; package com.android.inputmethod.dictionarypack;
import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
@ -55,6 +56,7 @@ public class MetadataHandler {
final int rawChecksumIndex = final int rawChecksumIndex =
results.getColumnIndex(MetadataDbHelper.RAW_CHECKSUM_COLUMN); results.getColumnIndex(MetadataDbHelper.RAW_CHECKSUM_COLUMN);
final int checksumIndex = results.getColumnIndex(MetadataDbHelper.CHECKSUM_COLUMN); final int checksumIndex = results.getColumnIndex(MetadataDbHelper.CHECKSUM_COLUMN);
final int retryCountIndex = results.getColumnIndex(MetadataDbHelper.RETRY_COUNT_COLUMN);
final int localFilenameIndex = final int localFilenameIndex =
results.getColumnIndex(MetadataDbHelper.LOCAL_FILENAME_COLUMN); results.getColumnIndex(MetadataDbHelper.LOCAL_FILENAME_COLUMN);
final int remoteFilenameIndex = final int remoteFilenameIndex =
@ -70,6 +72,7 @@ public class MetadataHandler {
results.getLong(fileSizeIndex), results.getLong(fileSizeIndex),
results.getString(rawChecksumIndex), results.getString(rawChecksumIndex),
results.getString(checksumIndex), results.getString(checksumIndex),
results.getInt(retryCountIndex),
results.getString(localFilenameIndex), results.getString(localFilenameIndex),
results.getString(remoteFilenameIndex), results.getString(remoteFilenameIndex),
results.getInt(versionIndex), 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. * Read metadata from a stream.
* @param input The stream to read from. * @param input The stream to read from.

View File

@ -83,6 +83,7 @@ public class MetadataParser {
Long.parseLong(arguments.get(FILESIZE_FIELD_NAME)), Long.parseLong(arguments.get(FILESIZE_FIELD_NAME)),
arguments.get(RAW_CHECKSUM_FIELD_NAME), arguments.get(RAW_CHECKSUM_FIELD_NAME),
arguments.get(CHECKSUM_FIELD_NAME), arguments.get(CHECKSUM_FIELD_NAME),
MetadataDbHelper.DICTIONARY_RETRY_THRESHOLD /* retryCount */,
null, null,
arguments.get(REMOTE_FILENAME_FIELD_NAME), arguments.get(REMOTE_FILENAME_FIELD_NAME),
Integer.parseInt(arguments.get(VERSION_FIELD_NAME)), Integer.parseInt(arguments.get(VERSION_FIELD_NAME)),

View File

@ -31,7 +31,6 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@ -785,6 +784,10 @@ public final class UpdateHandler {
} else { } else {
final SQLiteDatabase db = MetadataDbHelper.getDb(context, clientId); final SQLiteDatabase db = MetadataDbHelper.getDb(context, clientId);
if (newInfo.mVersion == currentInfo.mVersion) { 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. // 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. // It doesn't matter too much if they didn't change.
actions.add(new ActionBatch.UpdateDataAction(clientId, newInfo)); 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, public static void markAsUsed(final Context context, final String clientId,
final String wordlistId, final int version, final String wordlistId, final int version,
final int status, final boolean allowDownloadOnMeteredData) { final int status, final boolean allowDownloadOnMeteredData) {
final List<WordListMetadata> currentMetadata = final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
MetadataHandler.getCurrentMetadata(context, clientId); context, clientId, wordlistId, version);
WordListMetadata wordList = MetadataHandler.findWordListById(currentMetadata, wordlistId);
if (null == wordList) return; if (null == wordListMetaData) return;
final ActionBatch actions = new ActionBatch(); final ActionBatch actions = new ActionBatch();
if (MetadataDbHelper.STATUS_DISABLED == status if (MetadataDbHelper.STATUS_DISABLED == status
|| MetadataDbHelper.STATUS_DELETING == 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) { } else if (MetadataDbHelper.STATUS_AVAILABLE == status) {
actions.add(new ActionBatch.StartDownloadAction(clientId, wordList, actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData,
allowDownloadOnMeteredData)); allowDownloadOnMeteredData));
} else { } else {
Log.e(TAG, "Unexpected state of the word list for markAsUsed : " + status); Log.e(TAG, "Unexpected state of the word list for markAsUsed : " + status);
@ -1022,13 +1026,13 @@ public final class UpdateHandler {
// markAsUsed for consistency. // markAsUsed for consistency.
public static void markAsUnused(final Context context, final String clientId, public static void markAsUnused(final Context context, final String clientId,
final String wordlistId, final int version, final int status) { final String wordlistId, final int version, final int status) {
final List<WordListMetadata> currentMetadata =
MetadataHandler.getCurrentMetadata(context, clientId); final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
final WordListMetadata wordList = context, clientId, wordlistId, version);
MetadataHandler.findWordListById(currentMetadata, wordlistId);
if (null == wordList) return; if (null == wordListMetaData) return;
final ActionBatch actions = new ActionBatch(); 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)); actions.execute(context, new LogProblemReporter(TAG));
signalNewDictionaryState(context); signalNewDictionaryState(context);
} }
@ -1051,14 +1055,14 @@ public final class UpdateHandler {
*/ */
public static void markAsDeleting(final Context context, final String clientId, public static void markAsDeleting(final Context context, final String clientId,
final String wordlistId, final int version, final int status) { final String wordlistId, final int version, final int status) {
final List<WordListMetadata> currentMetadata =
MetadataHandler.getCurrentMetadata(context, clientId); final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
final WordListMetadata wordList = context, clientId, wordlistId, version);
MetadataHandler.findWordListById(currentMetadata, wordlistId);
if (null == wordList) return; if (null == wordListMetaData) return;
final ActionBatch actions = new ActionBatch(); final ActionBatch actions = new ActionBatch();
actions.add(new ActionBatch.DisableAction(clientId, wordList)); actions.add(new ActionBatch.DisableAction(clientId, wordListMetaData));
actions.add(new ActionBatch.StartDeleteAction(clientId, wordList)); actions.add(new ActionBatch.StartDeleteAction(clientId, wordListMetaData));
actions.execute(context, new LogProblemReporter(TAG)); actions.execute(context, new LogProblemReporter(TAG));
signalNewDictionaryState(context); signalNewDictionaryState(context);
} }
@ -1076,33 +1080,47 @@ public final class UpdateHandler {
*/ */
public static void markAsDeleted(final Context context, final String clientId, public static void markAsDeleted(final Context context, final String clientId,
final String wordlistId, final int version, final int status) { final String wordlistId, final int version, final int status) {
final List<WordListMetadata> currentMetadata = final WordListMetadata wordListMetaData = MetadataHandler.getCurrentMetadataForWordList(
MetadataHandler.getCurrentMetadata(context, clientId); context, clientId, wordlistId, version);
final WordListMetadata wordList =
MetadataHandler.findWordListById(currentMetadata, wordlistId); if (null == wordListMetaData) return;
if (null == wordList) return;
final ActionBatch actions = new ActionBatch(); 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)); actions.execute(context, new LogProblemReporter(TAG));
signalNewDictionaryState(context); signalNewDictionaryState(context);
} }
/** /**
* Marks the word list with the passed id as broken. * 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.
* 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.
* *
* @param context the context to open the database on. * @param context the context to open the database on.
* @param clientId the id of the client. * @param clientId the id of the client.
* @param wordlistId the id of the word list to mark as broken. * @param wordlistId the id of the word list which is broken.
* @param version the version of the word list to mark as deleted. * @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) { final String wordlistId, final int version) {
// TODO: do this on another thread to avoid blocking the UI. 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), MetadataDbHelper.deleteEntry(MetadataDbHelper.getDb(context, clientId),
wordlistId, version); wordlistId, version);
} }
}
} }

View File

@ -36,6 +36,7 @@ public class WordListMetadata {
public final String mRemoteFilename; public final String mRemoteFilename;
public final int mVersion; // version of this word list public final int mVersion; // version of this word list
public final int mFlags; // Always 0 in this version, reserved for future use 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 // 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 // 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, public WordListMetadata(final String id, final int type,
final String description, final long lastUpdate, final long fileSize, final String description, final long lastUpdate, final long fileSize,
final String rawChecksum, final String checksum, final String localFilename, final String rawChecksum, final String checksum, final int retryCount,
final String remoteFilename, final int version, final int formatVersion, final String localFilename, final String remoteFilename,
final int version, final int formatVersion,
final int flags, final String locale) { final int flags, final String locale) {
mId = id; mId = id;
mType = type; mType = type;
@ -61,6 +63,7 @@ public class WordListMetadata {
mFileSize = fileSize; mFileSize = fileSize;
mRawChecksum = rawChecksum; mRawChecksum = rawChecksum;
mChecksum = checksum; mChecksum = checksum;
mRetryCount = retryCount;
mLocalFilename = localFilename; mLocalFilename = localFilename;
mRemoteFilename = remoteFilename; mRemoteFilename = remoteFilename;
mVersion = version; mVersion = version;
@ -82,6 +85,7 @@ public class WordListMetadata {
final Long fileSize = values.getAsLong(MetadataDbHelper.FILESIZE_COLUMN); final Long fileSize = values.getAsLong(MetadataDbHelper.FILESIZE_COLUMN);
final String rawChecksum = values.getAsString(MetadataDbHelper.RAW_CHECKSUM_COLUMN); final String rawChecksum = values.getAsString(MetadataDbHelper.RAW_CHECKSUM_COLUMN);
final String checksum = values.getAsString(MetadataDbHelper.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 localFilename = values.getAsString(MetadataDbHelper.LOCAL_FILENAME_COLUMN);
final String remoteFilename = values.getAsString(MetadataDbHelper.REMOTE_FILENAME_COLUMN); final String remoteFilename = values.getAsString(MetadataDbHelper.REMOTE_FILENAME_COLUMN);
final Integer version = values.getAsInteger(MetadataDbHelper.VERSION_COLUMN); final Integer version = values.getAsInteger(MetadataDbHelper.VERSION_COLUMN);
@ -103,7 +107,8 @@ public class WordListMetadata {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
return new WordListMetadata(id, type, description, lastUpdate, fileSize, rawChecksum, 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 @Override
@ -116,6 +121,7 @@ public class WordListMetadata {
sb.append("\nFileSize : ").append(mFileSize); sb.append("\nFileSize : ").append(mFileSize);
sb.append("\nRawChecksum : ").append(mRawChecksum); sb.append("\nRawChecksum : ").append(mRawChecksum);
sb.append("\nChecksum : ").append(mChecksum); sb.append("\nChecksum : ").append(mChecksum);
sb.append("\nRetryCount: ").append(mRetryCount);
sb.append("\nLocalFilename : ").append(mLocalFilename); sb.append("\nLocalFilename : ").append(mLocalFilename);
sb.append("\nRemoteFilename : ").append(mRemoteFilename); sb.append("\nRemoteFilename : ").append(mRemoteFilename);
sb.append("\nVersion : ").append(mVersion); sb.append("\nVersion : ").append(mVersion);