diff options
Diffstat (limited to 'java/src/com/android/inputmethod/dictionarypack')
10 files changed, 280 insertions, 135 deletions
diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java index d5e638e7e..706bdea8e 100644 --- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java +++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java @@ -117,16 +117,11 @@ public final class ActionBatch { final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db, mWordList.mId, mWordList.mVersion); final int status = values.getAsInteger(MetadataDbHelper.STATUS_COLUMN); - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); if (MetadataDbHelper.STATUS_DOWNLOADING == status) { // The word list is still downloading. Cancel the download and revert the // word list status to "available". - if (null != manager) { - // DownloadManager is disabled (or not installed?). We can't cancel - there - // is nothing we can do. We still need to mark the entry as available. - manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN)); - } + manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN)); MetadataDbHelper.markEntryAsAvailable(db, mWordList.mId, mWordList.mVersion); } else if (MetadataDbHelper.STATUS_AVAILABLE != status) { // Should never happen @@ -136,9 +131,6 @@ public final class ActionBatch { // Download it. DebugLogUtils.l("Upgrade word list, downloading", mWordList.mRemoteFilename); - // TODO: if DownloadManager is disabled or not installed, download by ourselves - if (null == manager) return; - // This is an upgraded word list: we should download it. // 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 @@ -293,13 +285,8 @@ public final class ActionBatch { } // The word list is still downloading. Cancel the download and revert the // word list status to "available". - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - if (null != manager) { - // If we can't cancel the download because DownloadManager is not available, - // we still need to mark the entry as available. - manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN)); - } + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); + manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN)); MetadataDbHelper.markEntryAsAvailable(db, mWordList.mId, mWordList.mVersion); } } diff --git a/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java b/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java index 7c27e6d51..3d0e29ed0 100644 --- a/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java +++ b/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java @@ -23,7 +23,7 @@ public final class CommonPreferences { private static final String COMMON_PREFERENCES_NAME = "LatinImeDictPrefs"; public static SharedPreferences getCommonPreferences(final Context context) { - return context.getSharedPreferences(COMMON_PREFERENCES_NAME, Context.MODE_WORLD_READABLE); + return context.getSharedPreferences(COMMON_PREFERENCES_NAME, 0); } public static void enable(final SharedPreferences pref, final String id) { diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java index 88b5032e3..2623eff56 100644 --- a/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java +++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java @@ -100,32 +100,29 @@ public class DictionaryDownloadProgressBar extends ProgressBar { @Override protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); mIsCurrentlyAttachedToWindow = false; updateReporterThreadRunningStatusAccordingToVisibility(); } private class UpdaterThread extends Thread { private final static int REPORT_PERIOD = 150; // how often to report progress, in ms - final DownloadManager mDownloadManager; + final DownloadManagerWrapper mDownloadManagerWrapper; final int mId; public UpdaterThread(final Context context, final int id) { super(); - mDownloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + mDownloadManagerWrapper = new DownloadManagerWrapper(context); mId = id; } @Override public void run() { try { - // It's almost impossible that mDownloadManager is null (it would mean it has been - // disabled between pressing the 'install' button and displaying the progress - // bar), but just in case. - if (null == mDownloadManager) return; final UpdateHelper updateHelper = new UpdateHelper(); final Query query = new Query().setFilterById(mId); int lastProgress = 0; setIndeterminate(true); while (!isInterrupted()) { - final Cursor cursor = mDownloadManager.query(query); + final Cursor cursor = mDownloadManagerWrapper.query(query); if (null == cursor) { // Can't contact DownloadManager: this should never happen. return; diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java index 1d9b9991e..80def701d 100644 --- a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java +++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java @@ -350,7 +350,8 @@ public final class DictionaryProvider extends ContentProvider { clientId); if (null == results) { return Collections.<WordListInfo>emptyList(); - } else { + } + try { final HashMap<String, WordListInfo> dicts = new HashMap<String, WordListInfo>(); final int idIndex = results.getColumnIndex(MetadataDbHelper.WORDLISTID_COLUMN); final int localeIndex = results.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); @@ -416,8 +417,9 @@ public final class DictionaryProvider extends ContentProvider { } } while (results.moveToNext()); } - results.close(); return Collections.unmodifiableCollection(dicts.values()); + } finally { + results.close(); } } diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java index 7bbd041e7..dae2f22a4 100644 --- a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java +++ b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java @@ -283,59 +283,70 @@ public final class DictionarySettingsFragment extends PreferenceFragment final ArrayList<Preference> result = new ArrayList<Preference>(); result.add(createErrorMessage(activity, R.string.cannot_connect_to_dict_service)); return result; - } else if (!cursor.moveToFirst()) { - final ArrayList<Preference> result = new ArrayList<Preference>(); - result.add(createErrorMessage(activity, R.string.no_dictionaries_available)); - cursor.close(); - return result; - } else { - final String systemLocaleString = Locale.getDefault().toString(); - final TreeMap<String, WordListPreference> prefMap = - new TreeMap<String, WordListPreference>(); - final int idIndex = cursor.getColumnIndex(MetadataDbHelper.WORDLISTID_COLUMN); - final int versionIndex = cursor.getColumnIndex(MetadataDbHelper.VERSION_COLUMN); - final int localeIndex = cursor.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); - final int descriptionIndex = cursor.getColumnIndex(MetadataDbHelper.DESCRIPTION_COLUMN); - final int statusIndex = cursor.getColumnIndex(MetadataDbHelper.STATUS_COLUMN); - final int filesizeIndex = cursor.getColumnIndex(MetadataDbHelper.FILESIZE_COLUMN); - do { - final String wordlistId = cursor.getString(idIndex); - final int version = cursor.getInt(versionIndex); - final String localeString = cursor.getString(localeIndex); - final Locale locale = new Locale(localeString); - final String description = cursor.getString(descriptionIndex); - final int status = cursor.getInt(statusIndex); - final int matchLevel = LocaleUtils.getMatchLevel(systemLocaleString, localeString); - final String matchLevelString = LocaleUtils.getMatchLevelSortedString(matchLevel); - final int filesize = cursor.getInt(filesizeIndex); - // The key is sorted in lexicographic order, according to the match level, then - // the description. - final String key = matchLevelString + "." + description + "." + wordlistId; - final WordListPreference existingPref = prefMap.get(key); - if (null == existingPref || existingPref.hasPriorityOver(status)) { - final WordListPreference oldPreference = mCurrentPreferenceMap.get(key); - final WordListPreference pref; - if (null != oldPreference - && oldPreference.mVersion == version - && oldPreference.mLocale.equals(locale)) { - // If the old preference has all the new attributes, reuse it. We test - // for version and locale because although attributes other than status - // need to be the same, others have been tested through the key of the - // map. Also, status may differ so we don't want to use #equals() here. - pref = oldPreference; - pref.setStatus(status); - } else { - // Otherwise, discard it and create a new one instead. - pref = new WordListPreference(activity, mDictionaryListInterfaceState, - mClientId, wordlistId, version, locale, description, status, - filesize); + } + try { + if (!cursor.moveToFirst()) { + final ArrayList<Preference> result = new ArrayList<Preference>(); + result.add(createErrorMessage(activity, R.string.no_dictionaries_available)); + return result; + } else { + final String systemLocaleString = Locale.getDefault().toString(); + final TreeMap<String, WordListPreference> prefMap = + new TreeMap<String, WordListPreference>(); + final int idIndex = cursor.getColumnIndex(MetadataDbHelper.WORDLISTID_COLUMN); + final int versionIndex = cursor.getColumnIndex(MetadataDbHelper.VERSION_COLUMN); + final int localeIndex = cursor.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); + final int descriptionIndex = + cursor.getColumnIndex(MetadataDbHelper.DESCRIPTION_COLUMN); + final int statusIndex = cursor.getColumnIndex(MetadataDbHelper.STATUS_COLUMN); + final int filesizeIndex = cursor.getColumnIndex(MetadataDbHelper.FILESIZE_COLUMN); + do { + final String wordlistId = cursor.getString(idIndex); + final int version = cursor.getInt(versionIndex); + final String localeString = cursor.getString(localeIndex); + final Locale locale = new Locale(localeString); + final String description = cursor.getString(descriptionIndex); + final int status = cursor.getInt(statusIndex); + final int matchLevel = + LocaleUtils.getMatchLevel(systemLocaleString, localeString); + final String matchLevelString = + LocaleUtils.getMatchLevelSortedString(matchLevel); + final int filesize = cursor.getInt(filesizeIndex); + // The key is sorted in lexicographic order, according to the match level, then + // the description. + final String key = matchLevelString + "." + description + "." + wordlistId; + final WordListPreference existingPref = prefMap.get(key); + if (null == existingPref || existingPref.hasPriorityOver(status)) { + final WordListPreference oldPreference = mCurrentPreferenceMap.get(key); + final WordListPreference pref; + if (null != oldPreference + && oldPreference.mVersion == version + && oldPreference.hasStatus(status) + && oldPreference.mLocale.equals(locale)) { + // If the old preference has all the new attributes, reuse it. Ideally, + // we should reuse the old pref even if its status is different and call + // setStatus here, but setStatus calls Preference#setSummary() which + // needs to be done on the UI thread and we're not on the UI thread + // here. We could do all this work on the UI thread, but in this case + // it's probably lighter to stay on a background thread and throw this + // old preference out. + pref = oldPreference; + } else { + // Otherwise, discard it and create a new one instead. + // TODO: when the status is different from the old one, we need to + // animate the old one out before animating the new one in. + pref = new WordListPreference(activity, mDictionaryListInterfaceState, + mClientId, wordlistId, version, locale, description, status, + filesize); + } + prefMap.put(key, pref); } - prefMap.put(key, pref); - } - } while (cursor.moveToNext()); + } while (cursor.moveToNext()); + mCurrentPreferenceMap = prefMap; + return prefMap.values(); + } + } finally { cursor.close(); - mCurrentPreferenceMap = prefMap; - return prefMap.values(); } } diff --git a/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java new file mode 100644 index 000000000..75cc7d4cb --- /dev/null +++ b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 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.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteException; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.FileNotFoundException; + +/** + * A class to help with calling DownloadManager methods. + * + * Mostly, the problem here is that most methods from DownloadManager may throw SQL exceptions if + * they can't open the database on disk. We want to avoid crashing in these cases but can't do + * much more, so this class insulates the callers from these. SQLiteException also inherit from + * RuntimeException so they are unchecked :( + * While we're at it, we also insulate callers from the cases where DownloadManager is disabled, + * and getSystemService returns null. + */ +public class DownloadManagerWrapper { + private final static String TAG = DownloadManagerWrapper.class.getSimpleName(); + private final DownloadManager mDownloadManager; + + public DownloadManagerWrapper(final Context context) { + this((DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE)); + } + + private DownloadManagerWrapper(final DownloadManager downloadManager) { + mDownloadManager = downloadManager; + } + + public void remove(final long... ids) { + try { + if (null != mDownloadManager) { + mDownloadManager.remove(ids); + } + } catch (SQLiteException e) { + // We couldn't remove the file from DownloadManager. Apparently, the database can't + // be opened. It may be a problem with file system corruption. In any case, there is + // not much we can do apart from avoiding crashing. + Log.e(TAG, "Can't remove files with ID " + ids + " from download manager", e); + } catch (IllegalArgumentException e) { + // Not sure how this can happen, but it could be another case where the provider + // is disabled. Or it could be a bug in older versions of the framework. + Log.e(TAG, "Can't find the content URL for DownloadManager?", e); + } + } + + public ParcelFileDescriptor openDownloadedFile(final long fileId) throws FileNotFoundException { + try { + if (null != mDownloadManager) { + return mDownloadManager.openDownloadedFile(fileId); + } + } catch (SQLiteException e) { + Log.e(TAG, "Can't open downloaded file with ID " + fileId, e); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Can't find the content URL for DownloadManager?", e); + } + // We come here if mDownloadManager is null or if an exception was thrown. + throw new FileNotFoundException(); + } + + public Cursor query(final Query query) { + try { + if (null != mDownloadManager) { + return mDownloadManager.query(query); + } + } catch (SQLiteException e) { + Log.e(TAG, "Can't query the download manager", e); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Can't find the content URL for DownloadManager?", e); + } + // We come here if mDownloadManager is null or if an exception was thrown. + return null; + } + + public long enqueue(final Request request) { + try { + if (null != mDownloadManager) { + return mDownloadManager.enqueue(request); + } + } catch (SQLiteException e) { + Log.e(TAG, "Can't enqueue a request with the download manager", e); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Can't find the content URL for DownloadManager?", e); + } + return 0; + } +} diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java index ff5aba6d8..4a8fa51ee 100644 --- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java +++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java @@ -45,10 +45,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper { // 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; - // This is the current database version. It should be updated when the database schema - // gets updated. It is passed to the framework constructor of SQLiteOpenHelper, so - // that's what the framework uses to track our database version. - private static final int METADATA_DATABASE_VERSION = 6; + // The current database version. + private static final int CURRENT_METADATA_DATABASE_VERSION = 7; private final static long NOT_A_DOWNLOAD_ID = -1; @@ -169,7 +167,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper { private MetadataDbHelper(final Context context, final String clientId) { super(context, METADATA_DATABASE_NAME_STEM + (TextUtils.isEmpty(clientId) ? "" : "." + clientId), - null, METADATA_DATABASE_VERSION); + null, CURRENT_METADATA_DATABASE_VERSION); mContext = context; mClientId = clientId; } @@ -219,22 +217,45 @@ public class MetadataDbHelper extends SQLiteOpenHelper { /** * 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) { + && 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)) { - // Only the default database should contain the client table. - // Anyway in version 3 only the default table existed so the emptyness + // 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 { - // Version 3 was the earliest version, so we should never come here. If we do, we - // have no idea what this database is, so we'd better wipe it off. + // 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); @@ -533,12 +554,17 @@ public class MetadataDbHelper extends SQLiteOpenHelper { PENDINGID_COLUMN + "= ?", new String[] { Long.toString(id) }, null, null, null); - // 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. - final ContentValues result = getFirstLineAsContentValues(cursor); - cursor.close(); - return result; + 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(); + } } /** @@ -559,11 +585,16 @@ public class MetadataDbHelper extends SQLiteOpenHelper { new String[] { id, Integer.toString(STATUS_INSTALLED), Integer.toString(STATUS_DELETING) }, null, null, null); - // 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. - final ContentValues result = getFirstLineAsContentValues(cursor); - cursor.close(); - return result; + 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(); + } } /** @@ -622,10 +653,15 @@ public class MetadataDbHelper extends SQLiteOpenHelper { METADATA_TABLE_COLUMNS, WORDLISTID_COLUMN + "= ? AND " + VERSION_COLUMN + "= ?", new String[] { id, Integer.toString(version) }, null, null, null); - // This is a lookup by primary key, so there can't be more than one result. - final ContentValues result = getFirstLineAsContentValues(cursor); - cursor.close(); - return result; + 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(); + } } /** @@ -641,10 +677,15 @@ public class MetadataDbHelper extends SQLiteOpenHelper { METADATA_TABLE_COLUMNS, WORDLISTID_COLUMN + "= ?", new String[] { id }, null, null, VERSION_COLUMN + " DESC", "1"); - // This is a lookup by primary key, so there can't be more than one result. - final ContentValues result = getFirstLineAsContentValues(cursor); - cursor.close(); - return result; + 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(); + } } /** diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java b/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java index a0147b6d6..5c2289911 100644 --- a/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java +++ b/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java @@ -44,8 +44,7 @@ public class MetadataHandler { */ private static List<WordListMetadata> makeMetadataObject(final Cursor results) { final ArrayList<WordListMetadata> buildingMetadata = new ArrayList<WordListMetadata>(); - - if (results.moveToFirst()) { + if (null != results && results.moveToFirst()) { final int localeColumn = results.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); final int typeColumn = results.getColumnIndex(MetadataDbHelper.TYPE_COLUMN); final int descriptionColumn = @@ -61,7 +60,6 @@ public class MetadataHandler { final int versionIndex = results.getColumnIndex(MetadataDbHelper.VERSION_COLUMN); final int formatVersionIndex = results.getColumnIndex(MetadataDbHelper.FORMATVERSION_COLUMN); - do { buildingMetadata.add(new WordListMetadata(results.getString(idIndex), results.getInt(typeColumn), @@ -75,8 +73,6 @@ public class MetadataHandler { results.getInt(formatVersionIndex), 0, results.getString(localeColumn))); } while (results.moveToNext()); - - results.close(); } return Collections.unmodifiableList(buildingMetadata); } @@ -92,9 +88,14 @@ public class MetadataHandler { // If clientId is null, we get a cursor on the default database (see // MetadataDbHelper#getInstance() for more on this) final Cursor results = MetadataDbHelper.queryCurrentMetadata(context, clientId); - final List<WordListMetadata> resultList = makeMetadataObject(results); - results.close(); - return resultList; + // If null, we should return makeMetadataObject(null), so we go through. + try { + return makeMetadataObject(results); + } finally { + if (null != results) { + results.close(); + } + } } /** diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java index 0e7c3bb7e..dcff490db 100644 --- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java +++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java @@ -249,13 +249,7 @@ public final class UpdateHandler { metadataRequest.setVisibleInDownloadsUi( res.getBoolean(R.bool.metadata_downloads_visible_in_download_UI)); - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - if (null == manager) { - // Download manager is not installed or disabled. - // TODO: fall back to self-managed download? - return; - } + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); cancelUpdateWithDownloadManager(context, metadataUri, manager); final long downloadId; synchronized (sSharedIdProtector) { @@ -278,10 +272,10 @@ public final class UpdateHandler { * * @param context the context to open the database on * @param metadataUri the URI to cancel - * @param manager an instance of DownloadManager + * @param manager an wrapped instance of DownloadManager */ private static void cancelUpdateWithDownloadManager(final Context context, - final String metadataUri, final DownloadManager manager) { + final String metadataUri, final DownloadManagerWrapper manager) { synchronized (sSharedIdProtector) { final long metadataDownloadId = MetadataDbHelper.getMetadataDownloadIdForURI(context, metadataUri); @@ -306,10 +300,9 @@ public final class UpdateHandler { * @param clientId the ID of the client we want to cancel the update of */ public static void cancelUpdate(final Context context, final String clientId) { - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); final String metadataUri = MetadataDbHelper.getMetadataUriAsString(context, clientId); - if (null != manager) cancelUpdateWithDownloadManager(context, metadataUri, manager); + cancelUpdateWithDownloadManager(context, metadataUri, manager); } /** @@ -323,15 +316,15 @@ public final class UpdateHandler { * download request id, which is not known before submitting the request to the download * manager. Hence, it only updates the relevant line. * - * @param manager the download manager service to register the request with. + * @param manager a wrapped download manager service to register the request with. * @param request the request to register. * @param db the metadata database. * @param id the id of the word list. * @param version the version of the word list. * @return the download id returned by the download manager. */ - public static long registerDownloadRequest(final DownloadManager manager, final Request request, - final SQLiteDatabase db, final String id, final int version) { + 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); final long downloadId; synchronized (sSharedIdProtector) { @@ -345,8 +338,8 @@ public final class UpdateHandler { /** * Retrieve information about a specific download from DownloadManager. */ - private static CompletedDownloadInfo getCompletedDownloadInfo(final DownloadManager manager, - final long downloadId) { + private static CompletedDownloadInfo getCompletedDownloadInfo( + final DownloadManagerWrapper manager, final long downloadId) { final Query query = new Query().setFilterById(downloadId); final Cursor cursor = manager.query(query); @@ -425,8 +418,7 @@ public final class UpdateHandler { DebugLogUtils.l("DownloadFinished with id", fileId); if (NOT_AN_ID == fileId) return; // Spurious wake-up: ignore - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); final CompletedDownloadInfo downloadInfo = getCompletedDownloadInfo(manager, fileId); final ArrayList<DownloadRecord> recordList = @@ -517,7 +509,7 @@ public final class UpdateHandler { } private static boolean handleDownloadedFile(final Context context, - final DownloadRecord downloadRecord, final DownloadManager manager, + final DownloadRecord downloadRecord, final DownloadManagerWrapper manager, final long fileId) { try { // {@link handleWordList(Context,InputStream,ContentValues)}. diff --git a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java index ba1fce1a8..aea16af0d 100644 --- a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java +++ b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java @@ -98,6 +98,10 @@ public final class WordListPreference extends Preference { setSummary(getSummary(status)); } + public boolean hasStatus(final int status) { + return status == mStatus; + } + @Override public View onCreateView(final ViewGroup parent) { final View orphanedView = mInterfaceState.findFirstOrphanedView(); @@ -217,6 +221,7 @@ public final class WordListPreference extends Preference { progressBar.setIds(mClientId, mWordlistId); progressBar.setMax(mFilesize); final boolean showProgressBar = (MetadataDbHelper.STATUS_DOWNLOADING == mStatus); + setSummary(getSummary(mStatus)); status.setVisibility(showProgressBar ? View.INVISIBLE : View.VISIBLE); progressBar.setVisibility(showProgressBar ? View.VISIBLE : View.INVISIBLE); |