Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0d9c829 authored by Mohammadinamul Sheik's avatar Mohammadinamul Sheik
Browse files

Make the DictionaryService stage the downloaded files

Bug: 20641948
Change-Id: I6639c995b12c033bc30241cd219201dd483ee516
parent 459b4f35
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.inputmethod.latin.common;

import android.util.Log;

import java.io.File;
import java.io.FilenameFilter;

@@ -23,6 +25,8 @@ import java.io.FilenameFilter;
 * A simple class to help with removing directories recursively.
 */
public class FileUtils {
    private static final String TAG = "FileUtils";

    public static boolean deleteRecursively(final File path) {
        if (path.isDirectory()) {
            final File[] files = path.listFiles();
@@ -51,4 +55,14 @@ public class FileUtils {
        }
        return hasDeletedAllFiles;
    }

    public static boolean renameTo(final File fromFile, final File toFile) {
        toFile.delete();
        final boolean success = fromFile.renameTo(toFile);
        if (!success) {
            Log.e(TAG, String.format("Failed to rename from %s to %s.",
                    fromFile.getAbsoluteFile(), toFile.getAbsoluteFile()));
        }
        return  success;
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -26,7 +26,9 @@ import android.text.TextUtils;
import android.util.Log;

import com.android.inputmethod.compat.DownloadManagerCompatUtils;
import com.android.inputmethod.latin.BinaryDictionaryFileDumper;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.common.LocaleUtils;
import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;

@@ -210,9 +212,17 @@ public final class ActionBatch {
                        + " for an InstallAfterDownload action. Bailing out.");
                return;
            }

            DebugLogUtils.l("Setting word list as installed");
            final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
            MetadataDbHelper.markEntryAsFinishedDownloadingAndInstalled(db, mWordListValues);

            // Install the downloaded file by un-compressing and moving it to the staging
            // directory. Ideally, we should do this before updating the DB, but the
            // installDictToStagingFromContentProvider() relies on the db being updated.
            final String localeString = mWordListValues.getAsString(MetadataDbHelper.LOCALE_COLUMN);
            BinaryDictionaryFileDumper.installDictToStagingFromContentProvider(
                    LocaleUtils.constructLocaleFromString(localeString), context, false);
        }
    }

+2 −0
Original line number Diff line number Diff line
@@ -592,6 +592,8 @@ public final class UpdateHandler {
     * Warn Android Keyboard that the state of dictionaries changed and it should refresh its data.
     */
    private static void signalNewDictionaryState(final Context context) {
        // TODO: Also provide the locale of the updated dictionary so that the LatinIme
        // does not have to reset if it is a different locale.
        final Intent newDictBroadcast =
                new Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION);
        context.sendBroadcast(newDictBroadcast);
+26 −13
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.util.Log;

import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
import com.android.inputmethod.dictionarypack.MD5Calculator;
import com.android.inputmethod.latin.common.FileUtils;
import com.android.inputmethod.latin.define.DecoderSpecificConstants;
import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
import com.android.inputmethod.latin.utils.DictionaryInfoUtils.DictionaryInfo;
@@ -220,11 +221,11 @@ public final class BinaryDictionaryFileDumper {
    }

    /**
     * Caches a word list the id of which is passed as an argument. This will write the file
     * Stages a word list the id of which is passed as an argument. This will write the file
     * to the cache file name designated by its id and locale, overwriting it if already present
     * and creating it (and its containing directory) if necessary.
     */
    private static void cacheWordList(final String wordlistId, final String locale,
    private static void installWordListToStaging(final String wordlistId, final String locale,
            final String rawChecksum, final ContentProviderClient providerClient,
            final Context context) {
        final int COMPRESSED_CRYPTED_COMPRESSED = 0;
@@ -246,7 +247,7 @@ public final class BinaryDictionaryFileDumper {
            return;
        }
        final String finalFileName =
                DictionaryInfoUtils.getCacheFileName(wordlistId, locale, context);
                DictionaryInfoUtils.getStagingFileName(wordlistId, locale, context);
        String tempFileName;
        try {
            tempFileName = BinaryDictionaryGetter.getTempFileName(wordlistId, context);
@@ -320,23 +321,21 @@ public final class BinaryDictionaryFileDumper {
                    }
                }

                // move the output file to the final staging file.
                final File finalFile = new File(finalFileName);
                finalFile.delete();
                if (!outputFile.renameTo(finalFile)) {
                    throw new IOException("Can't move the file to its final name");
                }
                FileUtils.renameTo(outputFile, finalFile);

                wordListUriBuilder.appendQueryParameter(QUERY_PARAMETER_DELETE_RESULT,
                        QUERY_PARAMETER_SUCCESS);
                if (0 >= providerClient.delete(wordListUriBuilder.build(), null, null)) {
                    Log.e(TAG, "Could not have the dictionary pack delete a word list");
                }
                BinaryDictionaryGetter.removeFilesWithIdExcept(context, wordlistId, finalFile);
                Log.e(TAG, "Successfully copied file for wordlist ID " + wordlistId);
                Log.d(TAG, "Successfully copied file for wordlist ID " + wordlistId);
                // Success! Close files (through the finally{} clause) and return.
                return;
            } catch (Exception e) {
                if (DEBUG) {
                    Log.i(TAG, "Can't open word list in mode " + mode, e);
                    Log.e(TAG, "Can't open word list in mode " + mode, e);
                }
                if (null != outputFile) {
                    // This may or may not fail. The file may not have been created if the
@@ -403,7 +402,7 @@ public final class BinaryDictionaryFileDumper {
    }

    /**
     * Queries a content provider for word list data for some locale and cache the returned files
     * Queries a content provider for word list data for some locale and stage the returned files
     *
     * This will query a content provider for word list data for a given locale, and copy the
     * files locally so that they can be mmap'ed. This may overwrite previously cached word lists
@@ -411,7 +410,7 @@ public final class BinaryDictionaryFileDumper {
     * @throw FileNotFoundException if the provider returns non-existent data.
     * @throw IOException if the provider-returned data could not be read.
     */
    public static void cacheWordListsFromContentProvider(final Locale locale,
    public static void installDictToStagingFromContentProvider(final Locale locale,
            final Context context, final boolean hasDefaultWordList) {
        final ContentProviderClient providerClient;
        try {
@@ -429,13 +428,27 @@ public final class BinaryDictionaryFileDumper {
            final List<WordListInfo> idList = getWordListWordListInfos(locale, context,
                    hasDefaultWordList);
            for (WordListInfo id : idList) {
                cacheWordList(id.mId, id.mLocale, id.mRawChecksum, providerClient, context);
                installWordListToStaging(id.mId, id.mLocale, id.mRawChecksum, providerClient,
                        context);
            }
        } finally {
            providerClient.release();
        }
    }

    /**
     * Downloads the dictionary if it was never requested/used.
     *
     * @param locale locale to download
     * @param context the context for resources and providers.
     * @param hasDefaultWordList whether the default wordlist exists in the resources.
     */
    public static void downloadDictIfNeverRequested(final Locale locale,
            final Context context, final boolean hasDefaultWordList) {
        Log.d("inamul_tag", "BinaryDictionaryFileDumper.downloadDictIfNeverRequested()");
        getWordListWordListInfos(locale, context, hasDefaultWordList);
    }

    /**
     * Copies the data in an input stream to a target file if the magic number matches.
     *
+11 −38
Original line number Diff line number Diff line
@@ -195,39 +195,6 @@ final public class BinaryDictionaryGetter {
        return result;
    }

    /**
     * Remove all files with the passed id, except the passed file.
     *
     * If a dictionary with a given ID has a metadata change that causes it to change
     * path, we need to remove the old version. The only way to do this is to check all
     * installed files for a matching ID in a different directory.
     */
    public static void removeFilesWithIdExcept(final Context context, final String id,
            final File fileToKeep) {
        try {
            final File canonicalFileToKeep = fileToKeep.getCanonicalFile();
            final File[] directoryList = DictionaryInfoUtils.getCachedDirectoryList(context);
            if (null == directoryList) return;
            for (File directory : directoryList) {
                // There is one directory per locale. See #getCachedDirectoryList
                if (!directory.isDirectory()) continue;
                final File[] wordLists = directory.listFiles();
                if (null == wordLists) continue;
                for (File wordList : wordLists) {
                    final String fileId =
                            DictionaryInfoUtils.getWordListIdFromFileName(wordList.getName());
                    if (fileId.equals(id)) {
                        if (!canonicalFileToKeep.equals(wordList.getCanonicalFile())) {
                            wordList.delete();
                        }
                    }
                }
            }
        } catch (java.io.IOException e) {
            Log.e(TAG, "IOException trying to cleanup files", e);
        }
    }

    // ## HACK ## we prevent usage of a dictionary before version 18. The reason for this is, since
    // those do not include whitelist entries, the new code with an old version of the dictionary
    // would lose whitelist functionality.
@@ -274,12 +241,18 @@ final public class BinaryDictionaryGetter {
     */
    public static ArrayList<AssetFileAddress> getDictionaryFiles(final Locale locale,
            final Context context, boolean notifyDictionaryPackForUpdates) {

        if (notifyDictionaryPackForUpdates) {
            final boolean hasDefaultWordList = DictionaryInfoUtils.isDictionaryAvailable(
                    context, locale);
        if (notifyDictionaryPackForUpdates) {
            BinaryDictionaryFileDumper.cacheWordListsFromContentProvider(locale, context,
                    hasDefaultWordList);
            // It makes sure that the first time keyboard comes up and the dictionaries are reset,
            // the DB is populated with the appropriate values for each locale. Helps in downloading
            // the dictionaries when the user enables and switches new languages before the
            // DictionaryService runs.
            BinaryDictionaryFileDumper.downloadDictIfNeverRequested(
                    locale, context, hasDefaultWordList);

            // Move a staging files to the cache ddirectories if any.
            DictionaryInfoUtils.moveStagingFilesIfExists(context);
        }
        final File[] cachedWordLists = getCachedWordLists(locale.toString(), context);
        final String mainDictId = DictionaryInfoUtils.getMainDictId(locale);
Loading