Force download the dictionaries after the apk package is updated.

- Also display the notification when the dictionaries are auto updated


Bug: 19808828
Change-Id: If5c4efb73d8bb554d812afcf7deafec3ac40a462
This commit is contained in:
Mohammadinamul Sheik 2015-03-24 14:56:54 -07:00
parent e1b91d4138
commit 3bc3bc7971
10 changed files with 100 additions and 17 deletions

View File

@ -62,4 +62,11 @@ public class DictionaryPackConstants {
*/
public static final String UPDATE_NOW_INTENT_ACTION = DICTIONARY_DOMAIN
+ ".UPDATE_NOW";
/**
* The intent action to inform the dictionary provider to initialize the db
* and update now.
*/
public static final String INIT_AND_UPDATE_NOW_INTENT_ACTION = DICTIONARY_DOMAIN
+ ".INIT_AND_UPDATE_NOW";
}

View File

@ -144,6 +144,7 @@
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
<action android:name="android.intent.action.DATE_CHANGED" />
<action android:name="com.android.inputmethod.dictionarypack.aosp.UPDATE_NOW" />
<action android:name="com.android.inputmethod.dictionarypack.aosp.INIT_AND_UPDATE_NOW" />
</intent-filter>
</receiver>

View File

@ -25,6 +25,6 @@
<bool name="allow_over_roaming">false</bool>
<bool name="dict_downloads_visible_in_download_UI">false</bool>
<bool name="metadata_downloads_visible_in_download_UI">false</bool>
<bool name="display_notification_for_auto_update">false</bool>
<bool name="display_notification_for_user_requested_update">false</bool>
<bool name="display_notification_for_auto_update">true</bool>
<bool name="display_notification_for_user_requested_update">true</bool>
</resources>

View File

@ -173,7 +173,7 @@ public final class ActionBatch {
final long downloadId = UpdateHandler.registerDownloadRequest(manager, request, db,
mWordList.mId, mWordList.mVersion);
Log.i(TAG, String.format("Starting the dictionary download with version:"
+ " %d and Url: %s" + mWordList.mVersion, uri));
+ " %d and Url: %s", mWordList.mVersion, uri));
DebugLogUtils.l("Starting download of", uri, "with id", downloadId);
PrivateLog.log("Starting download of " + uri + ", id : " + downloadId);
}

View File

@ -22,6 +22,8 @@ import android.content.SharedPreferences;
public final class CommonPreferences {
private static final String COMMON_PREFERENCES_NAME = "LatinImeDictPrefs";
public static final String PREF_FORCE_DOWNLOAD_DICT = "pref_key_force_download_dict";
public static SharedPreferences getCommonPreferences(final Context context) {
return context.getSharedPreferences(COMMON_PREFERENCES_NAME, 0);
}
@ -37,4 +39,14 @@ public final class CommonPreferences {
editor.putBoolean(id, false);
editor.apply();
}
public static boolean isForceDownloadDict(Context context) {
return getCommonPreferences(context).getBoolean(PREF_FORCE_DOWNLOAD_DICT, false);
}
public static void setForceDownloadDict(Context context, boolean forceDownload) {
SharedPreferences.Editor editor = getCommonPreferences(context).edit();
editor.putBoolean(PREF_FORCE_DOWNLOAD_DICT, forceDownload);
editor.apply();
}
}

View File

@ -25,6 +25,7 @@ import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import com.android.inputmethod.latin.BinaryDictionaryFileDumper;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.common.LocaleUtils;
@ -192,13 +193,26 @@ public final class DictionaryService extends Service {
static void dispatchBroadcast(final Context context, final Intent intent) {
if (DATE_CHANGED_INTENT_ACTION.equals(intent.getAction())) {
// Do not force download dictionaries on date change updates.
CommonPreferences.setForceDownloadDict(context, false);
// This happens when the date of the device changes. This normally happens
// at midnight local time, but it may happen if the user changes the date
// by hand or something similar happens.
checkTimeAndMaybeSetupUpdateAlarm(context);
} else if (DictionaryPackConstants.UPDATE_NOW_INTENT_ACTION.equals(intent.getAction())) {
// Intent to trigger an update now.
UpdateHandler.tryUpdate(context, false);
UpdateHandler.tryUpdate(context, CommonPreferences.isForceDownloadDict(context));
} else if (DictionaryPackConstants.INIT_AND_UPDATE_NOW_INTENT_ACTION.equals(
intent.getAction())) {
// Enable force download of dictionaries irrespective of wifi or metered connection.
CommonPreferences.setForceDownloadDict(context, true);
// Initialize the client Db.
final String mClientId = context.getString(R.string.dictionary_pack_client_id);
BinaryDictionaryFileDumper.initializeClientRecordHelper(context, mClientId);
// Updates the metadata and the download the dictionaries.
UpdateHandler.tryUpdate(context, true);
} else {
UpdateHandler.downloadFinished(context, intent);
}
@ -249,7 +263,7 @@ public final class DictionaryService extends Service {
*/
public static void updateNowIfNotUpdatedInAVeryLongTime(final Context context) {
if (!isLastUpdateAtLeastThisOld(context, VERY_LONG_TIME_MILLIS)) return;
UpdateHandler.tryUpdate(context, false);
UpdateHandler.tryUpdate(context, CommonPreferences.isForceDownloadDict(context));
}
/**

View File

@ -264,6 +264,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper {
*/
@Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
// Allow automatic download of dictionaries on upgrading the database.
CommonPreferences.setForceDownloadDict(mContext, true);
if (METADATA_DATABASE_INITIAL_VERSION == oldVersion
&& METADATA_DATABASE_VERSION_WITH_CLIENTID <= newVersion
&& CURRENT_METADATA_DATABASE_VERSION >= newVersion) {

View File

@ -449,6 +449,8 @@ public final class UpdateHandler {
// download, so we are pretty sure it's alive. It's theoretically possible that it's
// disabled right inbetween the firing of the intent and the control reaching here.
boolean dictionaryDownloaded = false;
for (final DownloadRecord record : recordList) {
// downloadSuccessful is not final because we may still have exceptions from now on
boolean downloadSuccessful = false;
@ -463,9 +465,15 @@ public final class UpdateHandler {
final SQLiteDatabase db = MetadataDbHelper.getDb(context, record.mClientId);
publishUpdateWordListCompleted(context, downloadSuccessful, fileId,
db, record.mAttributes, record.mClientId);
dictionaryDownloaded = true;
}
}
}
if (dictionaryDownloaded) {
// Disable the force download after downloading the dictionaries.
CommonPreferences.setForceDownloadDict(context, false);
}
// Now that we're done using it, we can remove this download from DLManager
manager.remove(fileId);
}
@ -804,7 +812,7 @@ public final class UpdateHandler {
} else {
final SQLiteDatabase db = MetadataDbHelper.getDb(context, clientId);
if (newInfo.mVersion == currentInfo.mVersion) {
if (newInfo.mRemoteFilename == currentInfo.mRemoteFilename) {
if (TextUtils.equals(newInfo.mRemoteFilename, currentInfo.mRemoteFilename)) {
// If the dictionary url hasn't changed, we should preserve the retryCount.
newInfo.mRetryCount = currentInfo.mRetryCount;
}
@ -820,7 +828,8 @@ public final class UpdateHandler {
actions.add(new ActionBatch.MakeAvailableAction(clientId, newInfo));
if (status == MetadataDbHelper.STATUS_INSTALLED
|| status == MetadataDbHelper.STATUS_DISABLED) {
actions.add(new ActionBatch.StartDownloadAction(clientId, newInfo, false));
actions.add(new ActionBatch.StartDownloadAction(
clientId, newInfo, CommonPreferences.isForceDownloadDict(context)));
} else {
// Pass true to ForgetAction: this is indeed an update to a non-installed
// word list, so activate status == AVAILABLE check
@ -973,8 +982,10 @@ 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), false));
actions.add(new ActionBatch.StartDownloadAction(
clientId,
WordListMetadata.createFromContentValues(installCandidate),
CommonPreferences.isForceDownloadDict(context)));
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
@ -1020,8 +1031,9 @@ public final class UpdateHandler {
|| MetadataDbHelper.STATUS_DELETING == status) {
actions.add(new ActionBatch.EnableAction(clientId, wordListMetaData));
} else if (MetadataDbHelper.STATUS_AVAILABLE == status) {
boolean forceDownloadDict = CommonPreferences.isForceDownloadDict(context);
actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData,
allowDownloadOnMeteredData));
forceDownloadDict || allowDownloadOnMeteredData));
} else {
Log.e(TAG, "Unexpected state of the word list for markAsUsed : " + status);
}
@ -1133,7 +1145,8 @@ public final class UpdateHandler {
context, clientId, wordlistId, version);
final ActionBatch actions = new ActionBatch();
actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData, false));
actions.add(new ActionBatch.StartDownloadAction(
clientId, wordListMetaData, CommonPreferences.isForceDownloadDict(context)));
actions.execute(context, new LogProblemReporter(TAG));
} else {
if (DEBUG) {

View File

@ -27,6 +27,8 @@ import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.dictionarypack.CommonPreferences;
import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
import com.android.inputmethod.keyboard.KeyboardLayoutSet;
import com.android.inputmethod.latin.setup.SetupActivity;
import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
@ -70,6 +72,7 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes();
richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
toggleAppIcon(context);
downloadLatestDictionaries(context);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
Log.i(TAG, "Boot has been completed");
toggleAppIcon(context);
@ -97,6 +100,12 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
}
}
private void downloadLatestDictionaries(Context context) {
final Intent updateIntent = new Intent(
DictionaryPackConstants.INIT_AND_UPDATE_NOW_INTENT_ACTION);
context.sendBroadcast(updateIntent);
}
private static void toggleAppIcon(final Context context) {
final int appInfoFlags = context.getApplicationInfo().flags;
final boolean isSystemApp = (appInfoFlags & ApplicationInfo.FLAG_SYSTEM) > 0;

View File

@ -22,11 +22,13 @@ import android.content.res.AssetManager;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.Log;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.AssetFileAddress;
import com.android.inputmethod.latin.BinaryDictionaryGetter;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.common.LocaleUtils;
import com.android.inputmethod.latin.define.DecoderSpecificConstants;
import com.android.inputmethod.latin.makedict.DictionaryHeader;
@ -37,6 +39,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
@ -69,12 +72,11 @@ public class DictionaryInfoUtils {
public final Locale mLocale;
@Nullable
public final String mDescription;
@Nonnull
public final AssetFileAddress mFileAddress;
public final int mVersion;
public DictionaryInfo(@Nonnull final String id, @Nonnull final Locale locale,
@Nullable final String description, @Nonnull final AssetFileAddress fileAddress,
@Nullable final String description, @Nullable final AssetFileAddress fileAddress,
final int version) {
mId = id;
mLocale = locale;
@ -88,10 +90,12 @@ public class DictionaryInfoUtils {
values.put(WORDLISTID_COLUMN, mId);
values.put(LOCALE_COLUMN, mLocale.toString());
values.put(DESCRIPTION_COLUMN, mDescription);
values.put(LOCAL_FILENAME_COLUMN, mFileAddress.mFilename);
values.put(LOCAL_FILENAME_COLUMN,
mFileAddress != null ? mFileAddress.mFilename : "");
values.put(DATE_COLUMN, TimeUnit.MILLISECONDS.toSeconds(
new File(mFileAddress.mFilename).lastModified()));
values.put(FILESIZE_COLUMN, mFileAddress.mLength);
mFileAddress != null ? new File(mFileAddress.mFilename).lastModified() : 0));
values.put(FILESIZE_COLUMN,
mFileAddress != null ? mFileAddress.mLength : 0);
values.put(VERSION_COLUMN, mVersion);
return values;
}
@ -360,7 +364,6 @@ public class DictionaryInfoUtils {
* @param locale Locale for this file.
* @return information of the specified dictionary.
*/
@Nullable
private static DictionaryInfo createDictionaryInfoFromFileAddress(
final AssetFileAddress fileAddress, Locale locale) {
final String id = getMainDictId(locale);
@ -370,6 +373,17 @@ public class DictionaryInfoUtils {
return new DictionaryInfo(id, locale, description, fileAddress, version);
}
/**
* Returns dictionary information for the given locale.
*/
private static DictionaryInfo createDictionaryInfoFromLocale(Locale locale) {
final String id = getMainDictId(locale);
final int version = -1;
final String description = SubtypeLocaleUtils
.getSubtypeLocaleDisplayName(locale.toString());
return new DictionaryInfo(id, locale, description, null, version);
}
private static void addOrUpdateDictInfo(final ArrayList<DictionaryInfo> dictList,
final DictionaryInfo newElement) {
final Iterator<DictionaryInfo> iter = dictList.iterator();
@ -441,6 +455,17 @@ public class DictionaryInfoUtils {
addOrUpdateDictInfo(dictList, dictionaryInfo);
}
// Generate the dictionary information from the enabled subtypes. This will not
// overwrite the real records.
RichInputMethodManager.init(context);
List<InputMethodSubtype> enabledSubtypes = RichInputMethodManager
.getInstance().getMyEnabledInputMethodSubtypeList(true);
for (InputMethodSubtype subtype : enabledSubtypes) {
Locale locale = LocaleUtils.constructLocaleFromString(subtype.getLocale());
DictionaryInfo dictionaryInfo = createDictionaryInfoFromLocale(locale);
addOrUpdateDictInfo(dictList, dictionaryInfo);
}
return dictList;
}