From 3aad142435510feb575a6a9af0581fc84df6cabd Mon Sep 17 00:00:00 2001 From: Dan Zivkovic Date: Wed, 24 Jun 2015 17:40:52 -0700 Subject: [PATCH] Load metadata.json from resources on DB reset. This will ensure that a new (or upgraded) keyboard instance will know which dictionaries are available for download so it requests missing dictionaries. In addition, we increment the database version number to ensure upgrades of existing Fava instances start with a clean slate. Bug 22069694. Change-Id: Id71310412682543a3931f9c5c03cb0369fa7b9ac --- .../dictionarypack/MetadataDbHelper.java | 2 +- .../dictionarypack/UpdateHandler.java | 17 ++++++----- .../latin/BinaryDictionaryFileDumper.java | 28 +++++++++++++++++++ .../latin/utils/DictionaryInfoUtils.java | 9 +++++- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java index 78d13ebf9..7d01351b4 100644 --- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java +++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java @@ -50,7 +50,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper { 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 = 15; + private static final int CURRENT_METADATA_DATABASE_VERSION = 16; private final static long NOT_A_DOWNLOAD_ID = -1; diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java index d1e3c91dd..93725729c 100644 --- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java +++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java @@ -221,7 +221,7 @@ public final class UpdateHandler { */ private static void updateClientsWithMetadataUri( final Context context, final String metadataUri) { - PrivateLog.log("Update for metadata URI " + DebugLogUtils.s(metadataUri)); + Log.i(TAG, "updateClientsWithMetadataUri() : MetadataUri = " + metadataUri); // Adding a disambiguator to circumvent a bug in older versions of DownloadManager. // DownloadManager also stupidly cuts the extension to replace with its own that it // gets from the content-type. We need to circumvent this. @@ -255,7 +255,7 @@ public final class UpdateHandler { // method will ignore it. writeMetadataDownloadId(context, metadataUri, downloadId); } - PrivateLog.log("Requested download with id " + downloadId); + Log.i(TAG, "updateClientsWithMetadataUri() : DownloadId = " + downloadId); } /** @@ -327,11 +327,11 @@ public final class UpdateHandler { */ public static long registerDownloadRequest(final DownloadManagerWrapper manager, final Request request, final SQLiteDatabase db, final String id, final int version) { - DebugLogUtils.l("RegisterDownloadRequest for word list id : ", id, ", version ", version); + Log.i(TAG, "registerDownloadRequest() : Id = " + id + " : Version = " + version); final long downloadId; synchronized (sSharedIdProtector) { downloadId = manager.enqueue(request); - DebugLogUtils.l("Download requested with id", downloadId); + Log.i(TAG, "registerDownloadRequest() : DownloadId = " + downloadId); MetadataDbHelper.markEntryAsDownloading(db, id, version, downloadId); } return downloadId; @@ -582,7 +582,7 @@ public final class UpdateHandler { * @throws BadFormatException if the metadata is not in a known format. * @throws IOException if the downloaded file can't be read from the disk */ - private static void handleMetadata(final Context context, final InputStream stream, + public static void handleMetadata(final Context context, final InputStream stream, final String clientId) throws IOException, BadFormatException { DebugLogUtils.l("Entering handleMetadata"); final List newMetadata; @@ -905,6 +905,8 @@ public final class UpdateHandler { // word list ID / client ID combination. public static void installIfNeverRequested(final Context context, final String clientId, final String wordlistId, final boolean mayPrompt) { + Log.i(TAG, "installIfNeverRequested() : ClientId = " + clientId + + " : WordListId = " + wordlistId + " : MayPrompt = " + mayPrompt); final String[] idArray = wordlistId.split(DictionaryProvider.ID_CATEGORY_SEPARATOR); // If we have a new-format dictionary id (category:manual_id), then use the // specified category. Otherwise, it is a main dictionary, so force the @@ -959,8 +961,8 @@ public final class UpdateHandler { // change the shared preferences. So there is no way for a word list that has been // auto-installed once to get auto-installed again, and that's what we want. final ActionBatch actions = new ActionBatch(); - actions.add(new ActionBatch.StartDownloadAction( - clientId, WordListMetadata.createFromContentValues(installCandidate))); + WordListMetadata metadata = WordListMetadata.createFromContentValues(installCandidate); + actions.add(new ActionBatch.StartDownloadAction(clientId, metadata)); final String localeString = installCandidate.getAsString(MetadataDbHelper.LOCALE_COLUMN); // We are in a content provider: we can't do any UI at all. We have to defer the displaying // itself to the service. Also, we only display this when the user does not have a @@ -972,6 +974,7 @@ public final class UpdateHandler { intent.putExtra(DictionaryService.LOCALE_INTENT_ARGUMENT, localeString); context.startService(intent); } + Log.i(TAG, "installIfNeverRequested() : StartDownloadAction for " + metadata); actions.execute(context, new LogProblemReporter(TAG)); } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index afedde002..d25c1d373 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -29,6 +29,7 @@ import android.util.Log; import com.android.inputmethod.dictionarypack.DictionaryPackConstants; import com.android.inputmethod.dictionarypack.MD5Calculator; +import com.android.inputmethod.dictionarypack.UpdateHandler; import com.android.inputmethod.latin.common.FileUtils; import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.utils.DictionaryInfoUtils; @@ -487,6 +488,8 @@ public final class BinaryDictionaryFileDumper { private static void reinitializeClientRecordInDictionaryContentProvider(final Context context, final ContentProviderClient client, final String clientId) throws RemoteException { final String metadataFileUri = MetadataFileUriGetter.getMetadataUri(context); + Log.i(TAG, "reinitializeClientRecordInDictionaryContentProvider() : MetadataFileUri = " + + metadataFileUri); final String metadataAdditionalId = MetadataFileUriGetter.getMetadataAdditionalId(context); // Tell the content provider to reset all information about this client id final Uri metadataContentUri = getProviderUriBuilder(clientId) @@ -511,9 +514,34 @@ public final class BinaryDictionaryFileDumper { final int length = dictionaryList.size(); for (int i = 0; i < length; ++i) { final DictionaryInfo info = dictionaryList.get(i); + Log.i(TAG, "reinitializeClientRecordInDictionaryContentProvider() : Insert " + info); client.insert(Uri.withAppendedPath(dictionaryContentUriBase, info.mId), info.toContentValues()); } + + // Read from metadata file in resources to get the baseline dictionary info. + // This ensures we start with a sane list of available dictionaries. + final int metadataResourceId = context.getResources().getIdentifier("metadata", + "raw", DictionaryInfoUtils.RESOURCE_PACKAGE_NAME); + if (metadataResourceId == 0) { + Log.w(TAG, "Missing metadata.json resource"); + return; + } + InputStream inputStream = null; + try { + inputStream = context.getResources().openRawResource(metadataResourceId); + UpdateHandler.handleMetadata(context, inputStream, clientId); + } catch (Exception e) { + Log.w(TAG, "Failed to read metadata.json from resources", e); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + Log.w(TAG, "Failed to close metadata.json", e); + } + } + } } /** diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java index 096a545e5..11cccd5fa 100644 --- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java @@ -54,7 +54,7 @@ import javax.annotation.Nullable; */ public class DictionaryInfoUtils { private static final String TAG = DictionaryInfoUtils.class.getSimpleName(); - private static final String RESOURCE_PACKAGE_NAME = R.class.getPackage().getName(); + public static final String RESOURCE_PACKAGE_NAME = R.class.getPackage().getName(); private static final String DEFAULT_MAIN_DICT = "main"; private static final String MAIN_DICT_PREFIX = "main_"; private static final String DECODER_DICT_SUFFIX = DecoderSpecificConstants.DECODER_DICT_SUFFIX; @@ -103,6 +103,13 @@ public class DictionaryInfoUtils { values.put(VERSION_COLUMN, mVersion); return values; } + + @Override + public String toString() { + return "DictionaryInfo : Id = '" + mId + + "' : Locale=" + mLocale + + " : Version=" + mVersion; + } } private DictionaryInfoUtils() {