diff options
Diffstat (limited to 'ui/src/com/android/providers/downloads/ui/DownloadList.java')
-rw-r--r-- | ui/src/com/android/providers/downloads/ui/DownloadList.java | 147 |
1 files changed, 134 insertions, 13 deletions
diff --git a/ui/src/com/android/providers/downloads/ui/DownloadList.java b/ui/src/com/android/providers/downloads/ui/DownloadList.java index 1b7c727e..dd9a6083 100644 --- a/ui/src/com/android/providers/downloads/ui/DownloadList.java +++ b/ui/src/com/android/providers/downloads/ui/DownloadList.java @@ -21,11 +21,14 @@ import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; import android.content.Intent; +import android.database.ContentObserver; import android.database.Cursor; import android.net.DownloadManager; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.provider.Downloads; import android.view.Menu; import android.view.MenuInflater; @@ -44,6 +47,7 @@ import android.widget.Toast; import com.android.providers.downloads.ui.DownloadItem.DownloadSelectListener; +import java.io.File; import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -53,7 +57,7 @@ import java.util.Set; */ public class DownloadList extends Activity implements OnChildClickListener, OnItemClickListener, DownloadSelectListener, - OnClickListener { + OnClickListener, OnCancelListener { private ExpandableListView mDateOrderedListView; private ListView mSizeOrderedListView; private View mEmptyView; @@ -65,6 +69,7 @@ public class DownloadList extends Activity private DateSortedDownloadAdapter mDateSortedAdapter; private Cursor mSizeSortedCursor; private DownloadAdapter mSizeSortedAdapter; + private MyContentObserver mContentObserver = new MyContentObserver(); private int mStatusColumnId; private int mIdColumnId; @@ -74,14 +79,34 @@ public class DownloadList extends Activity private boolean mIsSortedBySize = false; private Set<Long> mSelectedIds = new HashSet<Long>(); + /** + * We keep track of when a dialog is being displayed for a pending download, because if that + * download starts running, we want to immediately hide the dialog. + */ + private Long mPendingDownloadId = null; + private AlertDialog mPendingDialog; + + private class MyContentObserver extends ContentObserver { + public MyContentObserver() { + super(new Handler()); + } + + @Override + public void onChange(boolean selfChange) { + handleDownloadsChanged(); + } + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setupViews(); mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); - mDateSortedCursor = mDownloadManager.query(new DownloadManager.Query()); - mSizeSortedCursor = mDownloadManager.query(new DownloadManager.Query() + DownloadManager.Query baseQuery = new DownloadManager.Query() + .setOnlyIncludeVisibleInDownloadsUi(true); + mDateSortedCursor = mDownloadManager.query(baseQuery); + mSizeSortedCursor = mDownloadManager.query(baseQuery .orderBy(DownloadManager.COLUMN_TOTAL_SIZE_BYTES, DownloadManager.Query.ORDER_DESCENDING)); @@ -131,15 +156,28 @@ public class DownloadList extends Activity mSelectionMenuView = (ViewGroup) findViewById(R.id.selection_menu); mSelectionDeleteButton = (Button) findViewById(R.id.selection_delete); mSelectionDeleteButton.setOnClickListener(this); + + ((Button) findViewById(R.id.deselect_all)).setOnClickListener(this); } @Override protected void onResume() { super.onResume(); + if (mDateSortedCursor != null) { + mDateSortedCursor.registerContentObserver(mContentObserver); + } refresh(); } @Override + protected void onPause() { + super.onPause(); + if (mDateSortedCursor != null) { + mDateSortedCursor.unregisterContentObserver(mContentObserver); + } + } + + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean("isSortedBySize", mIsSortedBySize); @@ -237,11 +275,28 @@ public class DownloadList extends Activity } /** + * @return an OnClickListener to restart the given downloadId in the Download Manager + */ + private DialogInterface.OnClickListener getRestartClickHandler(final long downloadId) { + return new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mDownloadManager.restartDownload(downloadId); + } + }; + } + + /** * Send an Intent to open the download currently pointed to by the given cursor. */ private void openCurrentDownload(Cursor cursor) { - Intent intent = new Intent(Intent.ACTION_VIEW); Uri fileUri = Uri.parse(cursor.getString(mLocalUriColumnId)); + if (!new File(fileUri.getPath()).exists()) { + showFailedDialog(cursor.getLong(mIdColumnId), R.string.dialog_file_missing_body); + return; + } + + Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(fileUri, cursor.getString(mMediaTypeColumnId)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { @@ -255,11 +310,13 @@ public class DownloadList extends Activity long id = cursor.getInt(mIdColumnId); switch (cursor.getInt(mStatusColumnId)) { case DownloadManager.STATUS_PENDING: - new AlertDialog.Builder(this) + mPendingDownloadId = id; + mPendingDialog = new AlertDialog.Builder(this) .setTitle(R.string.dialog_title_not_available) - .setMessage("This file is queued for future download.") + .setMessage(R.string.dialog_queued_body) .setPositiveButton(R.string.keep_queued_download, null) .setNegativeButton(R.string.remove_download, getDeleteClickHandler(id)) + .setOnCancelListener(this) .show(); break; @@ -273,16 +330,20 @@ public class DownloadList extends Activity break; case DownloadManager.STATUS_FAILED: - new AlertDialog.Builder(this) - .setTitle(R.string.dialog_title_not_available) - .setMessage(getResources().getString(R.string.dialog_failed_body)) - .setPositiveButton(R.string.remove_download, getDeleteClickHandler(id)) - // TODO button to retry download - .show(); + showFailedDialog(id, R.string.dialog_failed_body); break; } } + private void showFailedDialog(long downloadId, int dialogBodyResource) { + new AlertDialog.Builder(this) + .setTitle(R.string.dialog_title_not_available) + .setMessage(getResources().getString(dialogBodyResource)) + .setPositiveButton(R.string.remove_download, getDeleteClickHandler(downloadId)) + .setNegativeButton(R.string.retry_download, getRestartClickHandler(downloadId)) + .show(); + } + /** * TODO use constants/shared code? */ @@ -377,7 +438,11 @@ public class DownloadList extends Activity deleteDownload(downloadId); } clearSelection(); - return; + break; + + case R.id.deselect_all: + clearSelection(); + break; } } @@ -406,4 +471,60 @@ public class DownloadList extends Activity public boolean isDownloadSelected(long id) { return mSelectedIds.contains(id); } + + /** + * Called when there's a change to the downloads database. + */ + void handleDownloadsChanged() { + checkSelectionForDeletedEntries(); + + if (mPendingDownloadId != null && moveToDownload(mPendingDownloadId)) { + if (mDateSortedCursor.getInt(mStatusColumnId) != DownloadManager.STATUS_PENDING) { + mPendingDialog.cancel(); + } + } + } + + /** + * Check if any of the selected downloads have been deleted from the downloads database, and + * remove such downloads from the selection. + */ + private void checkSelectionForDeletedEntries() { + // gather all existing IDs... + Set<Long> allIds = new HashSet<Long>(); + for (mDateSortedCursor.moveToFirst(); !mDateSortedCursor.isAfterLast(); + mDateSortedCursor.moveToNext()) { + allIds.add(mDateSortedCursor.getLong(mIdColumnId)); + } + + // ...and check if any selected IDs are now missing + for (Iterator<Long> iterator = mSelectedIds.iterator(); iterator.hasNext(); ) { + if (!allIds.contains(iterator.next())) { + iterator.remove(); + } + } + } + + /** + * Move {@link #mDateSortedCursor} to the download with the given ID. + * @return true if the specified download ID was found; false otherwise + */ + private boolean moveToDownload(long downloadId) { + for (mDateSortedCursor.moveToFirst(); !mDateSortedCursor.isAfterLast(); + mDateSortedCursor.moveToNext()) { + if (mDateSortedCursor.getLong(mIdColumnId) == downloadId) { + return true; + } + } + return false; + } + + /** + * Called when a dialog for a pending download is canceled. + */ + @Override + public void onCancel(DialogInterface dialog) { + mPendingDownloadId = null; + mPendingDialog = null; + } } |