aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
diff options
context:
space:
mode:
authorAmin Bandali <bandali@kelar.org>2024-12-16 21:45:41 -0500
committerAmin Bandali <bandali@kelar.org>2025-01-11 14:17:35 -0500
commite9a0e66716dab4dd3184d009d8920de1961efdfa (patch)
tree02dcc096643d74645bf28459c2834c3d4a2ad7f2 /java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
parentfb3b9360d70596d7e921de8bf7d3ca99564a077e (diff)
downloadlatinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.gz
latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.xz
latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.zip
Rename to Kelar Keyboard (org.kelar.inputmethod.latin)
Diffstat (limited to 'java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java')
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java1155
1 files changed, 0 insertions, 1155 deletions
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
deleted file mode 100644
index 94dd7a1c9..000000000
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
+++ /dev/null
@@ -1,1155 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.dictionarypack;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.utils.DebugLogUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.TreeMap;
-
-import javax.annotation.Nullable;
-
-/**
- * Various helper functions for the state database
- */
-public class MetadataDbHelper extends SQLiteOpenHelper {
- private static final String TAG = MetadataDbHelper.class.getSimpleName();
-
- // This was the initial release version of the database. It should never be
- // changed going forward.
- private static final int METADATA_DATABASE_INITIAL_VERSION = 3;
- // This is the first released version of the database that implements CLIENTID. It is
- // 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.
- // This MUST be increased every time the dictionary pack metadata URL changes.
- private static final int CURRENT_METADATA_DATABASE_VERSION = 16;
-
- 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
- public static final String TYPE_COLUMN = "type";
- public static final String STATUS_COLUMN = "status";
- public static final String LOCALE_COLUMN = "locale";
- public static final String WORDLISTID_COLUMN = "id";
- public static final String DESCRIPTION_COLUMN = "description";
- public static final String LOCAL_FILENAME_COLUMN = "filename";
- public static final String REMOTE_FILENAME_COLUMN = "url";
- public static final String DATE_COLUMN = "date";
- public static final String CHECKSUM_COLUMN = "checksum";
- public static final String FILESIZE_COLUMN = "filesize";
- public static final String VERSION_COLUMN = "version";
- 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 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";
- private static final String CLIENT_METADATA_ADDITIONAL_ID_COLUMN = "additionalid";
- private static final String CLIENT_LAST_UPDATE_DATE_COLUMN = "lastupdate";
- private static final String CLIENT_PENDINGID_COLUMN = "pendingid"; // Download Manager ID
-
- public static final String METADATA_DATABASE_NAME_STEM = "pendingUpdates";
- public static final String METADATA_UPDATE_DESCRIPTION = "metadata";
-
- public static final String DICTIONARIES_ASSETS_PATH = "dictionaries";
-
- // Statuses, for storing in the STATUS_COLUMN
- // IMPORTANT: The following are used as index arrays in ../WordListPreference
- // Do not change their values without updating the matched code.
- // Unknown status: this should never happen.
- public static final int STATUS_UNKNOWN = 0;
- // Available: this word list is available, but it is not downloaded (not downloading), because
- // it is set not to be used.
- public static final int STATUS_AVAILABLE = 1;
- // Downloading: this word list is being downloaded.
- public static final int STATUS_DOWNLOADING = 2;
- // Installed: this word list is installed and usable.
- public static final int STATUS_INSTALLED = 3;
- // Disabled: this word list is installed, but has been disabled by the user.
- public static final int STATUS_DISABLED = 4;
- // 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.
- public static final int TYPE_METADATA = 1;
- // This is a bulk file. It should replace older files.
- public static final int TYPE_BULK = 2;
- // This is an incremental update, expected to be small, and meaningless on its own.
- public static final int TYPE_UPDATE = 3;
-
- private static final String METADATA_TABLE_CREATE =
- "CREATE TABLE " + METADATA_TABLE_NAME + " ("
- + PENDINGID_COLUMN + " INTEGER, "
- + TYPE_COLUMN + " INTEGER, "
- + STATUS_COLUMN + " INTEGER, "
- + WORDLISTID_COLUMN + " TEXT, "
- + LOCALE_COLUMN + " TEXT, "
- + DESCRIPTION_COLUMN + " TEXT, "
- + LOCAL_FILENAME_COLUMN + " TEXT, "
- + REMOTE_FILENAME_COLUMN + " TEXT, "
- + DATE_COLUMN + " INTEGER, "
- + CHECKSUM_COLUMN + " TEXT, "
- + FILESIZE_COLUMN + " INTEGER, "
- + VERSION_COLUMN + " INTEGER,"
- + 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 + " ("
- + CLIENT_CLIENT_ID_COLUMN + " TEXT, "
- + CLIENT_METADATA_URI_COLUMN + " TEXT, "
- + CLIENT_METADATA_ADDITIONAL_ID_COLUMN + " TEXT, "
- + CLIENT_LAST_UPDATE_DATE_COLUMN + " INTEGER NOT NULL DEFAULT 0, "
- + CLIENT_PENDINGID_COLUMN + " INTEGER, "
- + FLAGS_COLUMN + " INTEGER, "
- + "PRIMARY KEY (" + CLIENT_CLIENT_ID_COLUMN + "));";
-
- // List of all metadata table columns.
- static final String[] METADATA_TABLE_COLUMNS = { PENDINGID_COLUMN, TYPE_COLUMN,
- 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, 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 };
- // List of public columns returned to clients. Everything that is not in this list is
- // private and implementation-dependent.
- static final String[] DICTIONARIES_LIST_PUBLIC_COLUMNS = { STATUS_COLUMN, WORDLISTID_COLUMN,
- LOCALE_COLUMN, DESCRIPTION_COLUMN, DATE_COLUMN, FILESIZE_COLUMN, VERSION_COLUMN };
-
- // This class exhibits a singleton-like behavior by client ID, so it is getInstance'd
- // and has a private c'tor.
- private static TreeMap<String, MetadataDbHelper> sInstanceMap = null;
- public static synchronized MetadataDbHelper getInstance(final Context context,
- final String clientIdOrNull) {
- // As a backward compatibility feature, null can be passed here to retrieve the "default"
- // database. Before multi-client support, the dictionary packed used only one database
- // and would not be able to handle several dictionary sets. Passing null here retrieves
- // this legacy database. New clients should make sure to always pass a client ID so as
- // to avoid conflicts.
- final String clientId = null != clientIdOrNull ? clientIdOrNull : "";
- if (null == sInstanceMap) sInstanceMap = new TreeMap<>();
- MetadataDbHelper helper = sInstanceMap.get(clientId);
- if (null == helper) {
- helper = new MetadataDbHelper(context, clientId);
- sInstanceMap.put(clientId, helper);
- }
- return helper;
- }
- private MetadataDbHelper(final Context context, final String clientId) {
- super(context,
- METADATA_DATABASE_NAME_STEM + (TextUtils.isEmpty(clientId) ? "" : "." + clientId),
- null, CURRENT_METADATA_DATABASE_VERSION);
- mContext = context;
- mClientId = clientId;
- }
-
- private final Context mContext;
- private final String mClientId;
-
- /**
- * Get the database itself. This always returns the same object for any client ID. If the
- * client ID is null, a default database is returned for backward compatibility. Don't
- * pass null for new calls.
- *
- * @param context the context to create the database from. This is ignored after the first call.
- * @param clientId the client id to retrieve the database of. null for default (deprecated)
- * @return the database.
- */
- public static SQLiteDatabase getDb(final Context context, final String clientId) {
- return getInstance(context, clientId).getWritableDatabase();
- }
-
- private void createClientTable(final SQLiteDatabase db) {
- // The clients table only exists in the primary db, the one that has an empty client id
- if (!TextUtils.isEmpty(mClientId)) return;
- db.execSQL(METADATA_CREATE_CLIENT_TABLE);
- final String defaultMetadataUri = mContext.getString(R.string.default_metadata_uri);
- if (!TextUtils.isEmpty(defaultMetadataUri)) {
- final ContentValues defaultMetadataValues = new ContentValues();
- defaultMetadataValues.put(CLIENT_CLIENT_ID_COLUMN, "");
- defaultMetadataValues.put(CLIENT_METADATA_URI_COLUMN, defaultMetadataUri);
- defaultMetadataValues.put(CLIENT_PENDINGID_COLUMN, UpdateHandler.NOT_AN_ID);
- db.insert(CLIENT_TABLE_NAME, null, defaultMetadataValues);
- }
- }
-
- /**
- * Create the table and populate it with the resources found inside the apk.
- *
- * @see SQLiteOpenHelper#onCreate(SQLiteDatabase)
- *
- * @param db the database to create and populate.
- */
- @Override
- public void onCreate(final SQLiteDatabase db) {
- db.execSQL(METADATA_TABLE_CREATE);
- createClientTable(db);
- }
-
- private static void addRawChecksumColumnUnlessPresent(final SQLiteDatabase db) {
- try {
- db.execSQL("SELECT " + RAW_CHECKSUM_COLUMN + " FROM "
- + METADATA_TABLE_NAME + " LIMIT 0;");
- } catch (SQLiteException e) {
- Log.i(TAG, "No " + RAW_CHECKSUM_COLUMN + " column : creating it");
- db.execSQL("ALTER TABLE " + METADATA_TABLE_NAME + " ADD COLUMN "
- + RAW_CHECKSUM_COLUMN + " TEXT;");
- }
- }
-
- private static 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.
- * Version 6 and above has a DB named METADATA_DATABASE_NAME_STEM containing a
- * table CLIENT_TABLE_NAME, and for each client a table called METADATA_TABLE_STEM + "." + the
- * name of the client and contains a table METADATA_TABLE_NAME.
- * For schemas, see the above create statements. The schemas have never changed so far.
- *
- * This method is called by the framework. See {@link SQLiteOpenHelper#onUpgrade}
- * @param db The database we are upgrading
- * @param oldVersion The old database version (the one on the disk)
- * @param newVersion The new database version as supplied to the constructor of SQLiteOpenHelper
- */
- @Override
- public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
- if (METADATA_DATABASE_INITIAL_VERSION == oldVersion
- && METADATA_DATABASE_VERSION_WITH_CLIENTID <= newVersion
- && CURRENT_METADATA_DATABASE_VERSION >= newVersion) {
- // Upgrade from version METADATA_DATABASE_INITIAL_VERSION to version
- // METADATA_DATABASE_VERSION_WITH_CLIENT_ID
- // Only the default database should contain the client table, so we test for mClientId.
- if (TextUtils.isEmpty(mClientId)) {
- // Anyway in version 3 only the default table existed so the emptiness
- // test should always be true, but better check to be sure.
- createClientTable(db);
- }
- } else if (METADATA_DATABASE_VERSION_WITH_CLIENTID < newVersion
- && CURRENT_METADATA_DATABASE_VERSION >= newVersion) {
- // Here we drop the client table, so that all clients send us their information again.
- // The client table contains the URL to hit to update the available dictionaries list,
- // but the info about the dictionaries themselves is stored in the table called
- // METADATA_TABLE_NAME and we want to keep it, so we only drop the client table.
- db.execSQL("DROP TABLE IF EXISTS " + CLIENT_TABLE_NAME);
- // Only the default database should contain the client table, so we test for mClientId.
- if (TextUtils.isEmpty(mClientId)) {
- createClientTable(db);
- }
- } else {
- // If we're not in the above case, either we are upgrading from an earlier versionCode
- // and we should wipe the database, or we are handling a version we never heard about
- // (can only be a bug) so it's safer to wipe the database.
- db.execSQL("DROP TABLE IF EXISTS " + METADATA_TABLE_NAME);
- db.execSQL("DROP TABLE IF EXISTS " + CLIENT_TABLE_NAME);
- onCreate(db);
- }
- // A rawChecksum column that did not exist in the previous versions was added that
- // corresponds to the md5 checksum of the file after decompression/decryption. This is to
- // 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);
-
- // 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);
- }
-
- /**
- * Downgrade the database. This drops and recreates the table in all cases.
- */
- @Override
- public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
- // No matter what the numerical values of oldVersion and newVersion are, we know this
- // is a downgrade (newVersion < oldVersion). There is no way to know what the future
- // databases will look like, but we know it's extremely likely that it's okay to just
- // drop the tables and start from scratch. Hence, we ignore the versions and just wipe
- // everything we want to use.
- if (oldVersion <= newVersion) {
- Log.e(TAG, "onDowngrade database but new version is higher? " + oldVersion + " <= "
- + newVersion);
- }
- db.execSQL("DROP TABLE IF EXISTS " + METADATA_TABLE_NAME);
- db.execSQL("DROP TABLE IF EXISTS " + CLIENT_TABLE_NAME);
- onCreate(db);
- }
-
- /**
- * Given a client ID, returns whether this client exists.
- *
- * @param context a context to open the database
- * @param clientId the client ID to check
- * @return true if the client is known, false otherwise
- */
- public static boolean isClientKnown(final Context context, final String clientId) {
- // If the client is known, they'll have a non-null metadata URI. An empty string is
- // allowed as a metadata URI, if the client doesn't want any updates to happen.
- return null != getMetadataUriAsString(context, clientId);
- }
-
- private static final MetadataUriGetter sMetadataUriGetter = new MetadataUriGetter();
-
- /**
- * Returns the metadata URI as a string.
- *
- * If the client is not known, this will return null. If it is known, it will return
- * the URI as a string. Note that the empty string is a valid value.
- *
- * @param context a context instance to open the database on
- * @param clientId the ID of the client we want the metadata URI of
- * @return the string representation of the URI
- */
- public static String getMetadataUriAsString(final Context context, final String clientId) {
- SQLiteDatabase defaultDb = MetadataDbHelper.getDb(context, null);
- final Cursor cursor = defaultDb.query(MetadataDbHelper.CLIENT_TABLE_NAME,
- new String[] { MetadataDbHelper.CLIENT_METADATA_URI_COLUMN },
- MetadataDbHelper.CLIENT_CLIENT_ID_COLUMN + " = ?", new String[] { clientId },
- null, null, null, null);
- try {
- if (!cursor.moveToFirst()) return null;
- return sMetadataUriGetter.getUri(context, cursor.getString(0));
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Update the last metadata update time for all clients using a particular URI.
- *
- * This method searches for all clients using a particular URI and updates the last
- * update time for this client.
- * The current time is used as the latest update time. This saved date will be what
- * is returned henceforth by {@link #getLastUpdateDateForClient(Context, String)},
- * until this method is called again.
- *
- * @param context a context instance to open the database on
- * @param uri the metadata URI we just downloaded
- */
- public static void saveLastUpdateTimeOfUri(final Context context, final String uri) {
- PrivateLog.log("Save last update time of URI : " + uri + " " + System.currentTimeMillis());
- final ContentValues values = new ContentValues();
- values.put(CLIENT_LAST_UPDATE_DATE_COLUMN, System.currentTimeMillis());
- final SQLiteDatabase defaultDb = getDb(context, null);
- final Cursor cursor = MetadataDbHelper.queryClientIds(context);
- if (null == cursor) return;
- try {
- if (!cursor.moveToFirst()) return;
- do {
- final String clientId = cursor.getString(0);
- final String metadataUri =
- MetadataDbHelper.getMetadataUriAsString(context, clientId);
- if (metadataUri.equals(uri)) {
- defaultDb.update(CLIENT_TABLE_NAME, values,
- CLIENT_CLIENT_ID_COLUMN + " = ?", new String[] { clientId });
- }
- } while (cursor.moveToNext());
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Retrieves the last date at which we updated the metadata for this client.
- *
- * The returned date is in milliseconds from the EPOCH; this is the same unit as
- * returned by {@link System#currentTimeMillis()}.
- *
- * @param context a context instance to open the database on
- * @param clientId the client ID to get the latest update date of
- * @return the last date at which this client was updated, as a long.
- */
- public static long getLastUpdateDateForClient(final Context context, final String clientId) {
- SQLiteDatabase defaultDb = getDb(context, null);
- final Cursor cursor = defaultDb.query(CLIENT_TABLE_NAME,
- new String[] { CLIENT_LAST_UPDATE_DATE_COLUMN },
- CLIENT_CLIENT_ID_COLUMN + " = ?",
- new String[] { null == clientId ? "" : clientId },
- null, null, null, null);
- try {
- if (!cursor.moveToFirst()) return 0;
- return cursor.getLong(0); // Only one column, return it
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Get the metadata download ID for a metadata URI.
- *
- * This will retrieve the download ID for the metadata file that has the passed URI.
- * If this URI is not being downloaded right now, it will return NOT_AN_ID.
- *
- * @param context a context instance to open the database on
- * @param uri the URI to retrieve the metadata download ID of
- * @return the download id and start date, or null if the URL is not known
- */
- public static DownloadIdAndStartDate getMetadataDownloadIdAndStartDateForURI(
- final Context context, final String uri) {
- SQLiteDatabase defaultDb = getDb(context, null);
- final Cursor cursor = defaultDb.query(CLIENT_TABLE_NAME,
- new String[] { CLIENT_PENDINGID_COLUMN, CLIENT_LAST_UPDATE_DATE_COLUMN },
- CLIENT_METADATA_URI_COLUMN + " = ?", new String[] { uri },
- null, null, null, null);
- try {
- if (!cursor.moveToFirst()) return null;
- return new DownloadIdAndStartDate(cursor.getInt(0), cursor.getLong(1));
- } finally {
- cursor.close();
- }
- }
-
- public static long getOldestUpdateTime(final Context context) {
- SQLiteDatabase defaultDb = getDb(context, null);
- final Cursor cursor = defaultDb.query(CLIENT_TABLE_NAME,
- new String[] { CLIENT_LAST_UPDATE_DATE_COLUMN },
- null, null, null, null, null);
- try {
- if (!cursor.moveToFirst()) return 0;
- final int columnIndex = 0; // Only one column queried
- // Initialize the earliestTime to the largest possible value.
- long earliestTime = Long.MAX_VALUE; // Almost 300 million years in the future
- do {
- final long thisTime = cursor.getLong(columnIndex);
- earliestTime = Math.min(thisTime, earliestTime);
- } while (cursor.moveToNext());
- return earliestTime;
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Helper method to make content values to write into the database.
- * @return content values with all the arguments put with the right column names.
- */
- 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 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);
- result.put(WORDLISTID_COLUMN, wordlistId);
- result.put(STATUS_COLUMN, status);
- result.put(LOCALE_COLUMN, locale);
- result.put(DESCRIPTION_COLUMN, description);
- result.put(LOCAL_FILENAME_COLUMN, filename);
- 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);
- result.put(FORMATVERSION_COLUMN, formatVersion);
- result.put(FLAGS_COLUMN, 0);
- return result;
- }
-
- /**
- * Helper method to fill in an incomplete ContentValues with default values.
- * A wordlist ID and a locale are required, otherwise BadFormatException is thrown.
- * @return the same object that was passed in, completed with default values.
- */
- public static ContentValues completeWithDefaultValues(final ContentValues result)
- throws BadFormatException {
- if (null == result.get(WORDLISTID_COLUMN) || null == result.get(LOCALE_COLUMN)) {
- throw new BadFormatException();
- }
- // 0 for the pending id, because there is none
- if (null == result.get(PENDINGID_COLUMN)) result.put(PENDINGID_COLUMN, 0);
- // This is a binary blob of a dictionary
- if (null == result.get(TYPE_COLUMN)) result.put(TYPE_COLUMN, TYPE_BULK);
- // This word list is unknown, but it's present, else we wouldn't be here, so INSTALLED
- if (null == result.get(STATUS_COLUMN)) result.put(STATUS_COLUMN, STATUS_INSTALLED);
- // No description unless specified, because we can't guess it
- if (null == result.get(DESCRIPTION_COLUMN)) result.put(DESCRIPTION_COLUMN, "");
- // File name - this is an asset, so it works as an already deleted file.
- // hence, we need to supply a non-existent file name. Anything will
- // do as long as it returns false when tested with File#exist(), and
- // the empty string does not, so it's set to "_".
- if (null == result.get(LOCAL_FILENAME_COLUMN)) result.put(LOCAL_FILENAME_COLUMN, "_");
- // No remote file name : this can't be downloaded. Unless specified.
- if (null == result.get(REMOTE_FILENAME_COLUMN)) result.put(REMOTE_FILENAME_COLUMN, "");
- // 0 for the update date : 1970/1/1. Unless specified.
- 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
- if (null == result.get(FILESIZE_COLUMN)) result.put(FILESIZE_COLUMN, 0);
- // Smallest possible version unless specified
- if (null == result.get(VERSION_COLUMN)) result.put(VERSION_COLUMN, 1);
- // Assume current format unless specified
- if (null == result.get(FORMATVERSION_COLUMN))
- result.put(FORMATVERSION_COLUMN, UpdateHandler.MAXIMUM_SUPPORTED_FORMAT_VERSION);
- // No flags unless specified
- if (null == result.get(FLAGS_COLUMN)) result.put(FLAGS_COLUMN, 0);
- return result;
- }
-
- /**
- * Reads a column in a Cursor as a String and stores it in a ContentValues object.
- * @param result the ContentValues object to store the result in.
- * @param cursor the Cursor to read the column from.
- * @param columnId the column ID to read.
- */
- private static void putStringResult(ContentValues result, Cursor cursor, String columnId) {
- result.put(columnId, cursor.getString(cursor.getColumnIndex(columnId)));
- }
-
- /**
- * Reads a column in a Cursor as an int and stores it in a ContentValues object.
- * @param result the ContentValues object to store the result in.
- * @param cursor the Cursor to read the column from.
- * @param columnId the column ID to read.
- */
- private static void putIntResult(ContentValues result, Cursor cursor, String columnId) {
- result.put(columnId, cursor.getInt(cursor.getColumnIndex(columnId)));
- }
-
- private static ContentValues getFirstLineAsContentValues(final Cursor cursor) {
- final ContentValues result;
- if (cursor.moveToFirst()) {
- result = new ContentValues(COLUMN_COUNT);
- putIntResult(result, cursor, PENDINGID_COLUMN);
- putIntResult(result, cursor, TYPE_COLUMN);
- putIntResult(result, cursor, STATUS_COLUMN);
- putStringResult(result, cursor, WORDLISTID_COLUMN);
- putStringResult(result, cursor, LOCALE_COLUMN);
- putStringResult(result, cursor, DESCRIPTION_COLUMN);
- putStringResult(result, cursor, LOCAL_FILENAME_COLUMN);
- putStringResult(result, cursor, REMOTE_FILENAME_COLUMN);
- 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);
- putIntResult(result, cursor, FLAGS_COLUMN);
- if (cursor.moveToNext()) {
- // TODO: print the second level of the stack to the log so that we know
- // in which code path the error happened
- Log.e(TAG, "Several SQL results when we expected only one!");
- }
- } else {
- result = null;
- }
- return result;
- }
-
- /**
- * Gets the info about as specific download, indexed by its DownloadManager ID.
- * @param db the database to get the information from.
- * @param id the DownloadManager id.
- * @return metadata about this download. This returns all columns in the database.
- */
- public static ContentValues getContentValuesByPendingId(final SQLiteDatabase db,
- final long id) {
- final Cursor cursor = db.query(METADATA_TABLE_NAME,
- METADATA_TABLE_COLUMNS,
- PENDINGID_COLUMN + "= ?",
- new String[] { Long.toString(id) },
- null, null, null);
- if (null == cursor) {
- return null;
- }
- try {
- // There should never be more than one result. If because of some bug there are,
- // returning only one result is the right thing to do, because we couldn't handle
- // several anyway and we should still handle one.
- return getFirstLineAsContentValues(cursor);
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Gets the info about an installed OR deleting word list with a specified id.
- *
- * Basically, this is the word list that we want to return to Android Keyboard when
- * it asks for a specific id.
- *
- * @param db the database to get the information from.
- * @param id the word list ID.
- * @return the metadata about this word list.
- */
- public static ContentValues getInstalledOrDeletingWordListContentValuesByWordListId(
- final SQLiteDatabase db, final String id) {
- final Cursor cursor = db.query(METADATA_TABLE_NAME,
- METADATA_TABLE_COLUMNS,
- WORDLISTID_COLUMN + "=? AND (" + STATUS_COLUMN + "=? OR " + STATUS_COLUMN + "=?)",
- new String[] { id, Integer.toString(STATUS_INSTALLED),
- Integer.toString(STATUS_DELETING) },
- null, null, null);
- if (null == cursor) {
- return null;
- }
- try {
- // There should only be one result, but if there are several, we can't tell which
- // is the best, so we just return the first one.
- return getFirstLineAsContentValues(cursor);
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Given a specific download ID, return records for all pending downloads across all clients.
- *
- * If several clients use the same metadata URL, we know to only download it once, and
- * dispatch the update process across all relevant clients when the download ends. This means
- * several clients may share a single download ID if they share a metadata URI.
- * The dispatching is done in
- * {@link UpdateHandler#downloadFinished(Context, android.content.Intent)}, which
- * finds out about the list of relevant clients by calling this method.
- *
- * @param context a context instance to open the databases
- * @param downloadId the download ID to query about
- * @return the list of records. Never null, but may be empty.
- */
- public static ArrayList<DownloadRecord> getDownloadRecordsForDownloadId(final Context context,
- final long downloadId) {
- final SQLiteDatabase defaultDb = getDb(context, "");
- final ArrayList<DownloadRecord> results = new ArrayList<>();
- final Cursor cursor = defaultDb.query(CLIENT_TABLE_NAME, CLIENT_TABLE_COLUMNS,
- null, null, null, null, null);
- try {
- if (!cursor.moveToFirst()) return results;
- final int clientIdIndex = cursor.getColumnIndex(CLIENT_CLIENT_ID_COLUMN);
- final int pendingIdColumn = cursor.getColumnIndex(CLIENT_PENDINGID_COLUMN);
- do {
- final long pendingId = cursor.getInt(pendingIdColumn);
- final String clientId = cursor.getString(clientIdIndex);
- if (pendingId == downloadId) {
- results.add(new DownloadRecord(clientId, null));
- }
- final ContentValues valuesForThisClient =
- getContentValuesByPendingId(getDb(context, clientId), downloadId);
- if (null != valuesForThisClient) {
- results.add(new DownloadRecord(clientId, valuesForThisClient));
- }
- } while (cursor.moveToNext());
- } finally {
- cursor.close();
- }
- return results;
- }
-
- /**
- * Gets the info about a specific word list.
- *
- * @param db the database to get the information from.
- * @param id the word list ID.
- * @param version the word list version.
- * @return the metadata about this word list.
- */
- @Nullable
- public static ContentValues getContentValuesByWordListId(final SQLiteDatabase db,
- final String id, final int version) {
- final Cursor cursor = db.query(METADATA_TABLE_NAME,
- METADATA_TABLE_COLUMNS,
- 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;
- }
- try {
- // This is a lookup by primary key, so there can't be more than one result.
- return getFirstLineAsContentValues(cursor);
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Gets the info about the latest word list with an id.
- *
- * @param db the database to get the information from.
- * @param id the word list ID.
- * @return the metadata about the word list with this id and the latest version number.
- */
- public static ContentValues getContentValuesOfLatestAvailableWordlistById(
- final SQLiteDatabase db, final String id) {
- final Cursor cursor = db.query(METADATA_TABLE_NAME,
- METADATA_TABLE_COLUMNS,
- WORDLISTID_COLUMN + "= ?",
- new String[] { id }, null, null, VERSION_COLUMN + " DESC", "1");
- if (null == cursor) {
- return null;
- }
- try {
- // Return the first result from the list of results.
- return getFirstLineAsContentValues(cursor);
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Gets the current metadata about INSTALLED, AVAILABLE or DELETING dictionaries.
- *
- * This odd method is tailored to the needs of
- * DictionaryProvider#getDictionaryWordListsForContentUri, which needs the word list if
- * it is:
- * - INSTALLED: this should be returned to LatinIME if the file is still inside the dictionary
- * pack, so that it can be copied. If the file is not there, it's been copied already and should
- * not be returned, so getDictionaryWordListsForContentUri takes care of this.
- * - DELETING: this should be returned to LatinIME so that it can actually delete the file.
- * - AVAILABLE: this should not be returned, but should be checked for auto-installation.
- *
- * @param context the context for getting the database.
- * @param clientId the client id for retrieving the database. null for default (deprecated)
- * @return a cursor with metadata about usable dictionaries.
- */
- public static Cursor queryInstalledOrDeletingOrAvailableDictionaryMetadata(
- final Context context, final String clientId) {
- // If clientId is null, we get the defaut DB (see #getInstance() for more about this)
- final Cursor results = getDb(context, clientId).query(METADATA_TABLE_NAME,
- METADATA_TABLE_COLUMNS,
- STATUS_COLUMN + " = ? OR " + STATUS_COLUMN + " = ? OR " + STATUS_COLUMN + " = ?",
- new String[] { Integer.toString(STATUS_INSTALLED),
- Integer.toString(STATUS_DELETING),
- Integer.toString(STATUS_AVAILABLE) },
- null, null, LOCALE_COLUMN);
- return results;
- }
-
- /**
- * Gets the current metadata about all dictionaries.
- *
- * This will retrieve the metadata about all dictionaries, including
- * older files, or files not yet downloaded.
- *
- * @param context the context for getting the database.
- * @param clientId the client id for retrieving the database. null for default (deprecated)
- * @return a cursor with metadata about usable dictionaries.
- */
- public static Cursor queryCurrentMetadata(final Context context, final String clientId) {
- // If clientId is null, we get the defaut DB (see #getInstance() for more about this)
- final Cursor results = getDb(context, clientId).query(METADATA_TABLE_NAME,
- METADATA_TABLE_COLUMNS, null, null, null, null, LOCALE_COLUMN);
- return results;
- }
-
- /**
- * Gets the list of all dictionaries known to the dictionary provider, with only public columns.
- *
- * This will retrieve information about all known dictionaries, and their status. As such,
- * it will also return information about dictionaries on the server that have not been
- * downloaded yet, but may be requested.
- * This only returns public columns. It does not populate internal columns in the returned
- * cursor.
- * The value returned by this method is intended to be good to be returned directly for a
- * request of the list of dictionaries by a client.
- *
- * @param context the context to read the database from.
- * @param clientId the client id for retrieving the database. null for default (deprecated)
- * @return a cursor that lists all available dictionaries and their metadata.
- */
- public static Cursor queryDictionaries(final Context context, final String clientId) {
- // If clientId is null, we get the defaut DB (see #getInstance() for more about this)
- final Cursor results = getDb(context, clientId).query(METADATA_TABLE_NAME,
- DICTIONARIES_LIST_PUBLIC_COLUMNS,
- // Filter out empty locales so as not to return auxiliary data, like a
- // data line for downloading metadata:
- MetadataDbHelper.LOCALE_COLUMN + " != ?", new String[] {""},
- // TODO: Reinstate the following code for bulk, then implement partial updates
- /* MetadataDbHelper.TYPE_COLUMN + " = ?",
- new String[] { Integer.toString(MetadataDbHelper.TYPE_BULK) }, */
- null, null, LOCALE_COLUMN);
- return results;
- }
-
- /**
- * Deletes all data associated with a client.
- *
- * @param context the context for opening the database
- * @param clientId the ID of the client to delete.
- * @return true if the client was successfully deleted, false otherwise.
- */
- public static boolean deleteClient(final Context context, final String clientId) {
- // Remove all metadata associated with this client
- final SQLiteDatabase db = getDb(context, clientId);
- db.execSQL("DROP TABLE IF EXISTS " + METADATA_TABLE_NAME);
- db.execSQL(METADATA_TABLE_CREATE);
- // Remove this client's entry in the clients table
- final SQLiteDatabase defaultDb = getDb(context, "");
- if (0 == defaultDb.delete(CLIENT_TABLE_NAME,
- CLIENT_CLIENT_ID_COLUMN + " = ?", new String[] { clientId })) {
- return false;
- }
- return true;
- }
-
- /**
- * Updates information relative to a specific client.
- *
- * Updatable information includes the metadata URI and the additional ID column. It may be
- * expanded in the future.
- * The passed values must include a client ID in the key CLIENT_CLIENT_ID_COLUMN, and it must
- * be equal to the string passed as an argument for clientId. It may not be empty.
- * The passed values must also include a non-null metadata URI in the
- * CLIENT_METADATA_URI_COLUMN column, as well as a non-null additional ID in the
- * CLIENT_METADATA_ADDITIONAL_ID_COLUMN. Both these strings may be empty.
- * If any of the above is not complied with, this function returns without updating data.
- *
- * @param context the context, to open the database
- * @param clientId the ID of the client to update
- * @param values the values to update. Must conform to the protocol (see above)
- */
- public static void updateClientInfo(final Context context, final String clientId,
- final ContentValues values) {
- // Validity check the content values
- final String valuesClientId = values.getAsString(CLIENT_CLIENT_ID_COLUMN);
- final String valuesMetadataUri = values.getAsString(CLIENT_METADATA_URI_COLUMN);
- final String valuesMetadataAdditionalId =
- values.getAsString(CLIENT_METADATA_ADDITIONAL_ID_COLUMN);
- // Empty string is a valid client ID, but external apps may not configure it, so disallow
- // both null and empty string.
- // Empty string is a valid metadata URI if the client does not want updates, so allow
- // empty string but disallow null.
- // Empty string is a valid additional ID so allow empty string but disallow null.
- if (TextUtils.isEmpty(valuesClientId) || null == valuesMetadataUri
- || null == valuesMetadataAdditionalId) {
- // We need all these columns to be filled in
- DebugLogUtils.l("Missing parameter for updateClientInfo");
- return;
- }
- if (!clientId.equals(valuesClientId)) {
- // Mismatch! The client violates the protocol.
- DebugLogUtils.l("Received an updateClientInfo request for ", clientId,
- " but the values " + "contain a different ID : ", valuesClientId);
- return;
- }
- // Default value for a pending ID is NOT_AN_ID
- values.put(CLIENT_PENDINGID_COLUMN, UpdateHandler.NOT_AN_ID);
- final SQLiteDatabase defaultDb = getDb(context, "");
- if (-1 == defaultDb.insert(CLIENT_TABLE_NAME, null, values)) {
- defaultDb.update(CLIENT_TABLE_NAME, values,
- CLIENT_CLIENT_ID_COLUMN + " = ?", new String[] { clientId });
- }
- }
-
- /**
- * Retrieves the list of existing client IDs.
- * @param context the context to open the database
- * @return a cursor containing only one column, and one client ID per line.
- */
- public static Cursor queryClientIds(final Context context) {
- return getDb(context, null).query(CLIENT_TABLE_NAME,
- new String[] { CLIENT_CLIENT_ID_COLUMN }, null, null, null, null, null);
- }
-
- /**
- * Register a download ID for a specific metadata URI.
- *
- * This method should be called when a download for a metadata URI is starting. It will
- * search for all clients using this metadata URI and will register for each of them
- * the download ID into the database for later retrieval by
- * {@link #getDownloadRecordsForDownloadId(Context, long)}.
- *
- * @param context a context for opening databases
- * @param uri the metadata URI
- * @param downloadId the download ID
- */
- public static void registerMetadataDownloadId(final Context context, final String uri,
- final long downloadId) {
- final ContentValues values = new ContentValues();
- values.put(CLIENT_PENDINGID_COLUMN, downloadId);
- values.put(CLIENT_LAST_UPDATE_DATE_COLUMN, System.currentTimeMillis());
- final SQLiteDatabase defaultDb = getDb(context, "");
- final Cursor cursor = MetadataDbHelper.queryClientIds(context);
- if (null == cursor) return;
- try {
- if (!cursor.moveToFirst()) return;
- do {
- final String clientId = cursor.getString(0);
- final String metadataUri =
- MetadataDbHelper.getMetadataUriAsString(context, clientId);
- if (metadataUri.equals(uri)) {
- defaultDb.update(CLIENT_TABLE_NAME, values,
- CLIENT_CLIENT_ID_COLUMN + " = ?", new String[] { clientId });
- }
- } while (cursor.moveToNext());
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Marks a downloading entry as having successfully downloaded and being installed.
- *
- * The metadata database contains information about ongoing processes, typically ongoing
- * downloads. This marks such an entry as having finished and having installed successfully,
- * so it becomes INSTALLED.
- *
- * @param db the metadata database.
- * @param r content values about the entry to mark as processed.
- */
- public static void markEntryAsFinishedDownloadingAndInstalled(final SQLiteDatabase db,
- final ContentValues r) {
- switch (r.getAsInteger(TYPE_COLUMN)) {
- case TYPE_BULK:
- DebugLogUtils.l("Ended processing a wordlist");
- // Updating a bulk word list is a three-step operation:
- // - Add the new entry to the table
- // - Remove the old entry from the table
- // - Erase the old file
- // We start by gathering the names of the files we should delete.
- final List<String> filenames = new LinkedList<>();
- final Cursor c = db.query(METADATA_TABLE_NAME,
- new String[] { LOCAL_FILENAME_COLUMN },
- LOCALE_COLUMN + " = ? AND " +
- WORDLISTID_COLUMN + " = ? AND " + STATUS_COLUMN + " = ?",
- new String[] { r.getAsString(LOCALE_COLUMN),
- r.getAsString(WORDLISTID_COLUMN),
- Integer.toString(STATUS_INSTALLED) },
- null, null, null);
- try {
- if (c.moveToFirst()) {
- // There should never be more than one file, but if there are, it's a bug
- // and we should remove them all. I think it might happen if the power of
- // the phone is suddenly cut during an update.
- final int filenameIndex = c.getColumnIndex(LOCAL_FILENAME_COLUMN);
- do {
- DebugLogUtils.l("Setting for removal", c.getString(filenameIndex));
- filenames.add(c.getString(filenameIndex));
- } while (c.moveToNext());
- }
- } finally {
- c.close();
- }
- r.put(STATUS_COLUMN, STATUS_INSTALLED);
- db.beginTransactionNonExclusive();
- // Delete all old entries. There should never be any stalled entries, but if
- // there are, this deletes them.
- db.delete(METADATA_TABLE_NAME,
- WORDLISTID_COLUMN + " = ?",
- new String[] { r.getAsString(WORDLISTID_COLUMN) });
- db.insert(METADATA_TABLE_NAME, null, r);
- db.setTransactionSuccessful();
- db.endTransaction();
- for (String filename : filenames) {
- try {
- final File f = new File(filename);
- f.delete();
- } catch (SecurityException e) {
- // No permissions to delete. Um. Can't do anything.
- } // I don't think anything else can be thrown
- }
- break;
- default:
- // Unknown type: do nothing.
- break;
- }
- }
-
- /**
- * Removes a downloading entry from the database.
- *
- * This is invoked when a download fails. Either we tried to download, but
- * we received a permanent failure and we should remove it, or we got manually
- * cancelled and we should leave it at that.
- *
- * @param db the metadata database.
- * @param id the DownloadManager id of the file.
- */
- public static void deleteDownloadingEntry(final SQLiteDatabase db, final long id) {
- db.delete(METADATA_TABLE_NAME, PENDINGID_COLUMN + " = ? AND " + STATUS_COLUMN + " = ?",
- new String[] { Long.toString(id), Integer.toString(STATUS_DOWNLOADING) });
- }
-
- /**
- * Forcefully removes an entry from the database.
- *
- * This is invoked when a file is broken. The file has been downloaded, but Android
- * Keyboard is telling us it could not open it.
- *
- * @param db the metadata database.
- * @param id the id of the word list.
- * @param version the version of the word list.
- */
- public static void deleteEntry(final SQLiteDatabase db, final String id, final int version) {
- db.delete(METADATA_TABLE_NAME, WORDLISTID_COLUMN + " = ? AND " + VERSION_COLUMN + " = ?",
- new String[] { id, Integer.toString(version) });
- }
-
- /**
- * Internal method that sets the current status of an entry of the database.
- *
- * @param db the metadata database.
- * @param id the id of the word list.
- * @param version the version of the word list.
- * @param status the status to set the word list to.
- * @param downloadId an optional download id to write, or NOT_A_DOWNLOAD_ID
- */
- private static void markEntryAs(final SQLiteDatabase db, final String id,
- final int version, final int status, final long downloadId) {
- final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db, id, version);
- values.put(STATUS_COLUMN, status);
- if (NOT_A_DOWNLOAD_ID != downloadId) {
- values.put(MetadataDbHelper.PENDINGID_COLUMN, downloadId);
- }
- db.update(METADATA_TABLE_NAME, values,
- WORDLISTID_COLUMN + " = ? AND " + VERSION_COLUMN + " = ?",
- new String[] { id, Integer.toString(version) });
- }
-
- /**
- * Writes the status column for the wordlist with this id as enabled. Typically this
- * means the word list is currently disabled and we want to set its status to INSTALLED.
- *
- * @param db the metadata database.
- * @param id the id of the word list.
- * @param version the version of the word list.
- */
- public static void markEntryAsEnabled(final SQLiteDatabase db, final String id,
- final int version) {
- markEntryAs(db, id, version, STATUS_INSTALLED, NOT_A_DOWNLOAD_ID);
- }
-
- /**
- * Writes the status column for the wordlist with this id as disabled. Typically this
- * means the word list is currently installed and we want to set its status to DISABLED.
- *
- * @param db the metadata database.
- * @param id the id of the word list.
- * @param version the version of the word list.
- */
- public static void markEntryAsDisabled(final SQLiteDatabase db, final String id,
- final int version) {
- markEntryAs(db, id, version, STATUS_DISABLED, NOT_A_DOWNLOAD_ID);
- }
-
- /**
- * Writes the status column for the wordlist with this id as available. This happens for
- * example when a word list has been deleted but can be downloaded again.
- *
- * @param db the metadata database.
- * @param id the id of the word list.
- * @param version the version of the word list.
- */
- public static void markEntryAsAvailable(final SQLiteDatabase db, final String id,
- final int version) {
- markEntryAs(db, id, version, STATUS_AVAILABLE, NOT_A_DOWNLOAD_ID);
- }
-
- /**
- * Writes the designated word list as downloadable, alongside with its download id.
- *
- * @param db the metadata database.
- * @param id the id of the word list.
- * @param version the version of the word list.
- * @param downloadId the download id.
- */
- public static void markEntryAsDownloading(final SQLiteDatabase db, final String id,
- final int version, final long downloadId) {
- markEntryAs(db, id, version, STATUS_DOWNLOADING, downloadId);
- }
-
- /**
- * Writes the designated word list as deleting.
- *
- * @param db the metadata database.
- * @param id the id of the word list.
- * @param version the version of the word list.
- */
- public static void markEntryAsDeleting(final SQLiteDatabase db, final String id,
- 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;
- }
-}