aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean Chalard <jchalard@google.com>2014-02-17 16:14:18 +0900
committerJean Chalard <jchalard@google.com>2014-02-17 18:49:31 +0900
commita149731a6764f259b7d15e05a2f557a3bdd23aab (patch)
tree9d7c3e538a041e369828e7b24a1e5de491485b3c
parent4197c6f3ab1db7d37bfb5fca05bd7169504f451e (diff)
downloadlatinime-a149731a6764f259b7d15e05a2f557a3bdd23aab.tar.gz
latinime-a149731a6764f259b7d15e05a2f557a3bdd23aab.tar.xz
latinime-a149731a6764f259b7d15e05a2f557a3bdd23aab.zip
Catch exceptions we can't do anything about.
This also abstracts away the "package deactivated" case for simpler and safer code. Bug: 11072561 Change-Id: Idaaf2ae8d8d5b2c4a15de641bbf2f8c5c7cc9410
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/ActionBatch.java21
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java10
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java99
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java32
4 files changed, 118 insertions, 44 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/DictionaryDownloadProgressBar.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java
index 384ee3e07..2623eff56 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java
@@ -107,26 +107,22 @@ public class DictionaryDownloadProgressBar extends ProgressBar {
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/DownloadManagerWrapper.java b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java
new file mode 100644
index 000000000..e95ca1799
--- /dev/null
+++ b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java
@@ -0,0 +1,99 @@
+/*
+ * 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);
+ }
+ }
+
+ 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);
+ }
+ // 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);
+ }
+ // 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);
+ }
+ return 0;
+ }
+}
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)}.