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 public static final String UPDATE_NOW_INTENT_ACTION = DICTIONARY_DOMAIN
+ ".UPDATE_NOW"; + ".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.DOWNLOAD_COMPLETE" />
<action android:name="android.intent.action.DATE_CHANGED" /> <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.UPDATE_NOW" />
<action android:name="com.android.inputmethod.dictionarypack.aosp.INIT_AND_UPDATE_NOW" />
</intent-filter> </intent-filter>
</receiver> </receiver>

View File

@ -25,6 +25,6 @@
<bool name="allow_over_roaming">false</bool> <bool name="allow_over_roaming">false</bool>
<bool name="dict_downloads_visible_in_download_UI">false</bool> <bool name="dict_downloads_visible_in_download_UI">false</bool>
<bool name="metadata_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_auto_update">true</bool>
<bool name="display_notification_for_user_requested_update">false</bool> <bool name="display_notification_for_user_requested_update">true</bool>
</resources> </resources>

View File

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

View File

@ -22,6 +22,8 @@ import android.content.SharedPreferences;
public final class CommonPreferences { public final class CommonPreferences {
private static final String COMMON_PREFERENCES_NAME = "LatinImeDictPrefs"; 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) { public static SharedPreferences getCommonPreferences(final Context context) {
return context.getSharedPreferences(COMMON_PREFERENCES_NAME, 0); return context.getSharedPreferences(COMMON_PREFERENCES_NAME, 0);
} }
@ -37,4 +39,14 @@ public final class CommonPreferences {
editor.putBoolean(id, false); editor.putBoolean(id, false);
editor.apply(); 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.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.android.inputmethod.latin.BinaryDictionaryFileDumper;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.common.LocaleUtils; 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) { static void dispatchBroadcast(final Context context, final Intent intent) {
if (DATE_CHANGED_INTENT_ACTION.equals(intent.getAction())) { 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 // 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 // at midnight local time, but it may happen if the user changes the date
// by hand or something similar happens. // by hand or something similar happens.
checkTimeAndMaybeSetupUpdateAlarm(context); checkTimeAndMaybeSetupUpdateAlarm(context);
} else if (DictionaryPackConstants.UPDATE_NOW_INTENT_ACTION.equals(intent.getAction())) { } else if (DictionaryPackConstants.UPDATE_NOW_INTENT_ACTION.equals(intent.getAction())) {
// Intent to trigger an update now. // 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 { } else {
UpdateHandler.downloadFinished(context, intent); UpdateHandler.downloadFinished(context, intent);
} }
@ -249,7 +263,7 @@ public final class DictionaryService extends Service {
*/ */
public static void updateNowIfNotUpdatedInAVeryLongTime(final Context context) { public static void updateNowIfNotUpdatedInAVeryLongTime(final Context context) {
if (!isLastUpdateAtLeastThisOld(context, VERY_LONG_TIME_MILLIS)) return; 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 @Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { 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 if (METADATA_DATABASE_INITIAL_VERSION == oldVersion
&& METADATA_DATABASE_VERSION_WITH_CLIENTID <= newVersion && METADATA_DATABASE_VERSION_WITH_CLIENTID <= newVersion
&& CURRENT_METADATA_DATABASE_VERSION >= 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 // 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. // disabled right inbetween the firing of the intent and the control reaching here.
boolean dictionaryDownloaded = false;
for (final DownloadRecord record : recordList) { for (final DownloadRecord record : recordList) {
// downloadSuccessful is not final because we may still have exceptions from now on // downloadSuccessful is not final because we may still have exceptions from now on
boolean downloadSuccessful = false; boolean downloadSuccessful = false;
@ -463,9 +465,15 @@ public final class UpdateHandler {
final SQLiteDatabase db = MetadataDbHelper.getDb(context, record.mClientId); final SQLiteDatabase db = MetadataDbHelper.getDb(context, record.mClientId);
publishUpdateWordListCompleted(context, downloadSuccessful, fileId, publishUpdateWordListCompleted(context, downloadSuccessful, fileId,
db, record.mAttributes, record.mClientId); 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 // Now that we're done using it, we can remove this download from DLManager
manager.remove(fileId); manager.remove(fileId);
} }
@ -804,7 +812,7 @@ 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 (TextUtils.equals(newInfo.mRemoteFilename, currentInfo.mRemoteFilename)) {
// If the dictionary url hasn't changed, we should preserve the retryCount. // If the dictionary url hasn't changed, we should preserve the retryCount.
newInfo.mRetryCount = currentInfo.mRetryCount; newInfo.mRetryCount = currentInfo.mRetryCount;
} }
@ -820,7 +828,8 @@ public final class UpdateHandler {
actions.add(new ActionBatch.MakeAvailableAction(clientId, newInfo)); actions.add(new ActionBatch.MakeAvailableAction(clientId, newInfo));
if (status == MetadataDbHelper.STATUS_INSTALLED if (status == MetadataDbHelper.STATUS_INSTALLED
|| status == MetadataDbHelper.STATUS_DISABLED) { || status == MetadataDbHelper.STATUS_DISABLED) {
actions.add(new ActionBatch.StartDownloadAction(clientId, newInfo, false)); actions.add(new ActionBatch.StartDownloadAction(
clientId, newInfo, CommonPreferences.isForceDownloadDict(context)));
} else { } else {
// Pass true to ForgetAction: this is indeed an update to a non-installed // Pass true to ForgetAction: this is indeed an update to a non-installed
// word list, so activate status == AVAILABLE check // 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 // 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. // auto-installed once to get auto-installed again, and that's what we want.
final ActionBatch actions = new ActionBatch(); final ActionBatch actions = new ActionBatch();
actions.add(new ActionBatch.StartDownloadAction(clientId, actions.add(new ActionBatch.StartDownloadAction(
WordListMetadata.createFromContentValues(installCandidate), false)); clientId,
WordListMetadata.createFromContentValues(installCandidate),
CommonPreferences.isForceDownloadDict(context)));
final String localeString = installCandidate.getAsString(MetadataDbHelper.LOCALE_COLUMN); 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 // 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 // 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) { || MetadataDbHelper.STATUS_DELETING == status) {
actions.add(new ActionBatch.EnableAction(clientId, wordListMetaData)); actions.add(new ActionBatch.EnableAction(clientId, wordListMetaData));
} else if (MetadataDbHelper.STATUS_AVAILABLE == status) { } else if (MetadataDbHelper.STATUS_AVAILABLE == status) {
boolean forceDownloadDict = CommonPreferences.isForceDownloadDict(context);
actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData, actions.add(new ActionBatch.StartDownloadAction(clientId, wordListMetaData,
allowDownloadOnMeteredData)); forceDownloadDict || 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);
} }
@ -1133,7 +1145,8 @@ public final class UpdateHandler {
context, clientId, wordlistId, version); context, clientId, wordlistId, version);
final ActionBatch actions = new ActionBatch(); 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)); actions.execute(context, new LogProblemReporter(TAG));
} else { } else {
if (DEBUG) { if (DEBUG) {

View File

@ -27,6 +27,8 @@ import android.util.Log;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype; 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.keyboard.KeyboardLayoutSet;
import com.android.inputmethod.latin.setup.SetupActivity; import com.android.inputmethod.latin.setup.SetupActivity;
import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils; import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
@ -70,6 +72,7 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes(); final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes();
richImm.setAdditionalInputMethodSubtypes(additionalSubtypes); richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
toggleAppIcon(context); toggleAppIcon(context);
downloadLatestDictionaries(context);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) { } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
Log.i(TAG, "Boot has been completed"); Log.i(TAG, "Boot has been completed");
toggleAppIcon(context); 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) { private static void toggleAppIcon(final Context context) {
final int appInfoFlags = context.getApplicationInfo().flags; final int appInfoFlags = context.getApplicationInfo().flags;
final boolean isSystemApp = (appInfoFlags & ApplicationInfo.FLAG_SYSTEM) > 0; 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.content.res.Resources;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.AssetFileAddress; import com.android.inputmethod.latin.AssetFileAddress;
import com.android.inputmethod.latin.BinaryDictionaryGetter; import com.android.inputmethod.latin.BinaryDictionaryGetter;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.common.LocaleUtils;
import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.define.DecoderSpecificConstants;
import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.DictionaryHeader;
@ -37,6 +39,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -69,12 +72,11 @@ public class DictionaryInfoUtils {
public final Locale mLocale; public final Locale mLocale;
@Nullable @Nullable
public final String mDescription; public final String mDescription;
@Nonnull
public final AssetFileAddress mFileAddress; public final AssetFileAddress mFileAddress;
public final int mVersion; public final int mVersion;
public DictionaryInfo(@Nonnull final String id, @Nonnull final Locale locale, 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) { final int version) {
mId = id; mId = id;
mLocale = locale; mLocale = locale;
@ -88,10 +90,12 @@ public class DictionaryInfoUtils {
values.put(WORDLISTID_COLUMN, mId); values.put(WORDLISTID_COLUMN, mId);
values.put(LOCALE_COLUMN, mLocale.toString()); values.put(LOCALE_COLUMN, mLocale.toString());
values.put(DESCRIPTION_COLUMN, mDescription); 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( values.put(DATE_COLUMN, TimeUnit.MILLISECONDS.toSeconds(
new File(mFileAddress.mFilename).lastModified())); mFileAddress != null ? new File(mFileAddress.mFilename).lastModified() : 0));
values.put(FILESIZE_COLUMN, mFileAddress.mLength); values.put(FILESIZE_COLUMN,
mFileAddress != null ? mFileAddress.mLength : 0);
values.put(VERSION_COLUMN, mVersion); values.put(VERSION_COLUMN, mVersion);
return values; return values;
} }
@ -360,7 +364,6 @@ public class DictionaryInfoUtils {
* @param locale Locale for this file. * @param locale Locale for this file.
* @return information of the specified dictionary. * @return information of the specified dictionary.
*/ */
@Nullable
private static DictionaryInfo createDictionaryInfoFromFileAddress( private static DictionaryInfo createDictionaryInfoFromFileAddress(
final AssetFileAddress fileAddress, Locale locale) { final AssetFileAddress fileAddress, Locale locale) {
final String id = getMainDictId(locale); final String id = getMainDictId(locale);
@ -370,6 +373,17 @@ public class DictionaryInfoUtils {
return new DictionaryInfo(id, locale, description, fileAddress, version); 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, private static void addOrUpdateDictInfo(final ArrayList<DictionaryInfo> dictList,
final DictionaryInfo newElement) { final DictionaryInfo newElement) {
final Iterator<DictionaryInfo> iter = dictList.iterator(); final Iterator<DictionaryInfo> iter = dictList.iterator();
@ -441,6 +455,17 @@ public class DictionaryInfoUtils {
addOrUpdateDictInfo(dictList, dictionaryInfo); 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; return dictList;
} }