Merge "Attempt retry for broken dictionaries"
commit
972003428b
|
@ -120,9 +120,10 @@ public final class ActionBatch {
|
||||||
if (MetadataDbHelper.STATUS_DOWNLOADING == status) {
|
if (MetadataDbHelper.STATUS_DOWNLOADING == status) {
|
||||||
// The word list is still downloading. Cancel the download and revert the
|
// The word list is still downloading. Cancel the download and revert the
|
||||||
// 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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
|
@ -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.deleteEntry(MetadataDbHelper.getDb(context, clientId),
|
MetadataDbHelper.getDb(context, clientId), wordlistId, version);
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue