bug:3308769 add CAB options to downloads app
Vasu Nori [Thu, 24 Feb 2011 00:49:09 +0000 (16:49 -0800)]
Change-Id: I9bb1374b7ca0053210274e5d6981b2f2dcf6bfca

ui/AndroidManifest.xml
ui/res/layout/download_list.xml
ui/res/menu/download_menu.xml
ui/res/values/strings.xml
ui/src/com/android/providers/downloads/ui/DateSortedDownloadAdapter.java
ui/src/com/android/providers/downloads/ui/DateSortedExpandableListAdapter.java
ui/src/com/android/providers/downloads/ui/DownloadAdapter.java
ui/src/com/android/providers/downloads/ui/DownloadItem.java
ui/src/com/android/providers/downloads/ui/DownloadList.java

index 1b4af38..04d1863 100644 (file)
@@ -11,7 +11,9 @@
                  android:icon="@mipmap/ic_launcher_download"
                  android:hardwareAccelerated="true">
         <activity android:name=".DownloadList"
-                  android:launchMode="singleTop">
+                  android:launchMode="singleTop"
+                  android:theme="@android:style/Theme.Holo.DialogWhenLarge">
+
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
index 8f75bae..395d79a 100644 (file)
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:orientation="vertical">
-    <!-- The main area showing the list of downloads -->
-    <FrameLayout android:layout_width="match_parent"
-                 android:layout_height="match_parent"
-                 android:layout_weight="1">
+
         <ExpandableListView android:id="@+id/date_ordered_list"
                             android:layout_width="match_parent"
                             android:layout_height="match_parent"/>
                   android:text="@string/no_downloads"
                   android:gravity="center"
                   android:textStyle="bold"/>
-    </FrameLayout>
-
-    <!-- The selection menu that pops up from the bottom of the screen -->
-    <LinearLayout android:id="@+id/selection_menu"
-                  android:orientation="horizontal"
-                  android:visibility="gone"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:paddingTop="5dip"
-                  android:paddingLeft="4dip"
-                  android:paddingRight="4dip"
-                  android:paddingBottom="1dip"
-                  android:gravity="center"
-                  android:layout_gravity="center"
-                  android:background="@android:drawable/bottom_bar">
-          <Button android:id="@+id/selection_delete"
-                  android:layout_width="match_parent"
-                  android:layout_height="match_parent"
-                  android:layout_weight="1"/>
-          <Button android:id="@+id/deselect_all"
-                  android:layout_width="match_parent"
-                  android:layout_height="match_parent"
-                  android:layout_weight="1"
-                  android:text="@string/deselect_all"/>
-
-      </LinearLayout>
 </LinearLayout>
index 6dbcb6e..95cb673 100644 (file)
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:id="@+id/download_menu_sort_by_size"
         android:title="@string/download_menu_sort_by_size"
-        android:icon="@android:drawable/ic_menu_sort_by_size" />
+        android:icon="@android:drawable/ic_menu_sort_by_size"
+        android:showAsAction="ifRoom" />
+
     <item android:id="@+id/download_menu_sort_by_date"
         android:title="@string/download_menu_sort_by_date"
-        android:icon="@drawable/ic_menu_desk_clock" />
+        android:showAsAction="ifRoom" />
+
+    <item android:id="@+id/delete_download"
+          android:title="@string/delete_download"
+          android:icon="@android:drawable/ic_menu_delete"
+          android:showAsAction="ifRoom" />
+
+    <item android:id="@+id/select_all"
+          android:title="@string/select_all"
+          android:showAsAction="ifRoom" />
 </menu>
index 07f5152..0be08dd 100644 (file)
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- The name of the application that appears in the launcher [CHAR LIMIT=15] -->
     <string name="app_label">Downloads</string>
-    <!-- The title that appears at the top of the activity listing downloads [CHAR LIMIT=25] -->
-    <string name="download_title">Downloads</string>
+    <!-- The title that appears at the top of the activity listing downloads sorted by date [CHAR LIMIT=40] -->
+    <string name="download_title_sorted_by_date">Downloads - Sorted by date</string>
+    <!-- The title that appears at the top of the activity listing downloads sorted by size [CHAR LIMIT=40] -->
+    <string name="download_title_sorted_by_size">Downloads - Sorted by size</string>
 
     <!-- Appears in lieu of the list of downloads if there are no downloads to view
          [CHAR LIMIT=200] -->
@@ -34,7 +36,7 @@
     <string name="download_menu_sort_by_size">Sort by size</string>
     <!-- Menu option to sort the list of downloads by the date/time of the last activity related to
          the download [CHAR LIMIT=25] -->
-    <string name="download_menu_sort_by_date">Sort by time</string>
+    <string name="download_menu_sort_by_date">Sort by date</string>
 
     <!-- Status messages -->
 
     <string name="retry_download">Retry</string>
     <!-- Text for button appearing in the pop-up selection menu to deselect all currently selected
     downloads in the download list [CHAR LIMIT=25] -->
-    <string name="deselect_all">Clear selection</string>
+    <string name="deselect_all">Deselect All</string>
+    <!-- Text for menu to select all downloads in the download list [CHAR LIMIT=25] -->
+    <string name="select_all">Select All</string>
+    <!-- number of downloads selected [CHAR LIMIT=50] -->
+    <string name="selected_count">Selected %1$d out of %2$d</string>
+
 </resources>
index 8c34782..8e93eab 100644 (file)
 
 package com.android.providers.downloads.ui;
 
-import com.android.providers.downloads.ui.DownloadItem.DownloadSelectListener;
-
 import android.app.DownloadManager;
-import android.content.Context;
 import android.database.Cursor;
 import android.view.View;
 import android.view.ViewGroup;
@@ -33,11 +30,10 @@ import android.widget.RelativeLayout;
 public class DateSortedDownloadAdapter extends DateSortedExpandableListAdapter {
     private DownloadAdapter mDelegate;
 
-    public DateSortedDownloadAdapter(Context context, Cursor cursor,
-            DownloadSelectListener selectionListener) {
-        super(context, cursor,
+    public DateSortedDownloadAdapter(DownloadList downloadList, Cursor cursor) {
+        super(downloadList, cursor,
                 cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP));
-        mDelegate = new DownloadAdapter(context, cursor, selectionListener);
+        mDelegate = new DownloadAdapter(downloadList, cursor);
     }
 
     @Override
@@ -53,7 +49,8 @@ public class DateSortedDownloadAdapter extends DateSortedExpandableListAdapter {
             return convertView;
         }
 
-        mDelegate.bindView(convertView);
+        int pos = getAbsolutePositionForGroupAndChildPositions(groupPosition, childPosition);
+        mDelegate.bindView(convertView, pos);
         return convertView;
     }
 }
index 19132a1..73c51ae 100644 (file)
@@ -226,6 +226,19 @@ public class DateSortedExpandableListAdapter implements ExpandableListAdapter {
         return arrayPosition;
     }
 
+    int getAbsolutePositionForGroupAndChildPositions(int groupPosition,
+            int childPosition) {
+        int bin = groupPositionToBin(groupPosition);
+        int absolutePosition = 0;
+        for (int j = 0; j < bin; j++) {
+            if (mItemMap[j] > 0) {
+                absolutePosition += mItemMap[j] + 1;
+            }
+        }
+        absolutePosition += childPosition + 1;
+        return absolutePosition;
+    }
+
     /**
      * Move the cursor to the position indicated.
      * @param packedPosition Position in packed position representation.
index c0a916c..e8bea08 100644 (file)
@@ -35,8 +35,6 @@ import android.widget.CursorAdapter;
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import com.android.providers.downloads.ui.DownloadItem.DownloadSelectListener;
-
 import java.text.DateFormat;
 import java.util.Calendar;
 import java.util.Date;
@@ -47,9 +45,8 @@ import java.util.List;
  * List adapter for Cursors returned by {@link DownloadManager}.
  */
 public class DownloadAdapter extends CursorAdapter {
-    private Context mContext;
+    private final DownloadList mDownloadList;
     private Cursor mCursor;
-    private DownloadSelectListener mDownloadSelectionListener;
     private Resources mResources;
     private DateFormat mDateFormat;
     private DateFormat mTimeFormat;
@@ -63,13 +60,11 @@ public class DownloadAdapter extends CursorAdapter {
     private int mDateColumnId;
     private int mIdColumnId;
 
-    public DownloadAdapter(Context context, Cursor cursor,
-            DownloadSelectListener selectionListener) {
-        super(context, cursor);
-        mContext = context;
+    public DownloadAdapter(DownloadList downloadList, Cursor cursor) {
+        super(downloadList, cursor);
+        mDownloadList = downloadList;
         mCursor = cursor;
-        mResources = mContext.getResources();
-        mDownloadSelectionListener = selectionListener;
+        mResources = mDownloadList.getResources();
         mDateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
         mTimeFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
 
@@ -85,19 +80,20 @@ public class DownloadAdapter extends CursorAdapter {
     }
 
     public View newView() {
-        DownloadItem view = (DownloadItem) LayoutInflater.from(mContext)
+        DownloadItem view = (DownloadItem) LayoutInflater.from(mDownloadList)
                 .inflate(R.layout.download_list_item, null);
-        view.setSelectListener(mDownloadSelectionListener);
+        view.setDownloadListObj(mDownloadList);
         return view;
     }
 
-    public void bindView(View convertView) {
+    public void bindView(View convertView, int position) {
         if (!(convertView instanceof DownloadItem)) {
             return;
         }
 
         long downloadId = mCursor.getLong(mIdColumnId);
-        ((DownloadItem) convertView).setDownloadId(downloadId);
+        ((DownloadItem) convertView).setData(downloadId, position);
+        
 
         // Retrieve the icon for this download
         retrieveAndSetIcon(convertView);
@@ -113,7 +109,7 @@ public class DownloadAdapter extends CursorAdapter {
         setTextForView(convertView, R.id.last_modified_date, getDateString());
 
         CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.download_checkbox);
-        checkBox.setChecked(mDownloadSelectionListener.isDownloadSelected(downloadId));
+        checkBox.setChecked(mDownloadList.isDownloadSelected(downloadId));
     }
 
     private String getDateString() {
@@ -207,6 +203,6 @@ public class DownloadAdapter extends CursorAdapter {
 
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
-        bindView(view);
+        bindView(view, cursor.getPosition());
     }
 }
index c462d59..86eb7f4 100644 (file)
@@ -20,6 +20,7 @@ import android.content.Context;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.widget.CheckBox;
+import android.widget.Checkable;
 import android.widget.RelativeLayout;
 
 /**
@@ -28,18 +29,14 @@ import android.widget.RelativeLayout;
  * also keeps an ID associated with the currently displayed download and notifies a listener upon
  * selection changes with that ID.
  */
-public class DownloadItem extends RelativeLayout {
+public class DownloadItem extends RelativeLayout implements Checkable {
     private static float CHECKMARK_AREA = -1;
 
     private boolean mIsInDownEvent = false;
     private CheckBox mCheckBox;
     private long mDownloadId;
-    private DownloadSelectListener mListener;
-
-    static interface DownloadSelectListener {
-        public void onDownloadSelectionChanged(long downloadId, boolean isSelected);
-        public boolean isDownloadSelected(long id);
-    }
+    private DownloadList mDownloadList;
+    private int mPosition;
 
     public DownloadItem(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
@@ -68,12 +65,13 @@ public class DownloadItem extends RelativeLayout {
         mCheckBox = (CheckBox) findViewById(R.id.download_checkbox);
     }
 
-    public void setDownloadId(long downloadId) {
+    public void setData(long downloadId, int position) {
         mDownloadId = downloadId;
+        mPosition = position;
     }
 
-    public void setSelectListener(DownloadSelectListener listener) {
-        mListener = listener;
+    public void setDownloadListObj(DownloadList downloadList) {
+        mDownloadList = downloadList;
     }
 
     @Override
@@ -93,7 +91,7 @@ public class DownloadItem extends RelativeLayout {
 
             case MotionEvent.ACTION_UP:
                 if (mIsInDownEvent && event.getX() < CHECKMARK_AREA) {
-                    toggleCheckMark();
+                    toggle();
                     handled = true;
                 }
                 mIsInDownEvent = false;
@@ -109,8 +107,20 @@ public class DownloadItem extends RelativeLayout {
         return handled;
     }
 
-    private void toggleCheckMark() {
-        mCheckBox.toggle();
-        mListener.onDownloadSelectionChanged(mDownloadId, mCheckBox.isChecked());
+    @Override
+    public boolean isChecked() {
+        return mCheckBox.isChecked();
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        mCheckBox.setChecked(checked);
+        mDownloadList.onDownloadSelectionChanged(mDownloadId, mCheckBox.isChecked());
+        mDownloadList.getCurrentView().setItemChecked(mPosition, mCheckBox.isChecked());
+    }
+
+    @Override
+    public void toggle() {
+        setChecked(!isChecked());
     }
 }
index 23d0d8f..3de6484 100644 (file)
@@ -23,7 +23,6 @@ import android.content.ActivityNotFoundException;
 import android.content.ContentUris;
 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;
@@ -34,23 +33,20 @@ import android.os.Environment;
 import android.os.Handler;
 import android.provider.Downloads;
 import android.util.Log;
+import android.util.SparseBooleanArray;
+import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
+import android.widget.AbsListView.MultiChoiceModeListener;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
-import android.widget.Button;
 import android.widget.ExpandableListView;
 import android.widget.ExpandableListView.OnChildClickListener;
 import android.widget.ListView;
 import android.widget.Toast;
 
-import com.android.providers.downloads.ui.DownloadItem.DownloadSelectListener;
-
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.HashSet;
@@ -60,16 +56,12 @@ import java.util.Set;
 /**
  *  View showing a list of all downloads the Download Manager knows about.
  */
-public class DownloadList extends Activity
-        implements OnChildClickListener, OnItemClickListener, DownloadSelectListener,
-        OnClickListener, OnCancelListener {
+public class DownloadList extends Activity {
     private static final String LOG_TAG = "DownloadList";
 
     private ExpandableListView mDateOrderedListView;
     private ListView mSizeOrderedListView;
     private View mEmptyView;
-    private ViewGroup mSelectionMenuView;
-    private Button mSelectionDeleteButton;
 
     private DownloadManager mDownloadManager;
     private Cursor mDateSortedCursor;
@@ -84,10 +76,11 @@ public class DownloadList extends Activity
     private int mLocalUriColumnId;
     private int mMediaTypeColumnId;
     private int mReasonColumndId;
-    private int mMediaProviderUriId;
 
+    private final Set<Long> mSelectedIds = new HashSet<Long>();
+    ListView mCurrentView;
+    Cursor mCurrentCursor;
     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
@@ -95,6 +88,7 @@ public class DownloadList extends Activity
      */
     private Long mQueuedDownloadId = null;
     private AlertDialog mQueuedDialog;
+    String mSelectedCountFormat;
 
 
     private class MyContentObserver extends ContentObserver {
@@ -120,12 +114,14 @@ public class DownloadList extends Activity
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
+        setFinishOnTouchOutside(true);
         setupViews();
 
         mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
         mDownloadManager.setAccessAllDownloads(true);
         DownloadManager.Query baseQuery = new DownloadManager.Query()
                 .setOnlyIncludeVisibleInDownloadsUi(true);
+        //TODO don't do both queries - do them as needed
         mDateSortedCursor = mDownloadManager.query(baseQuery);
         mSizeSortedCursor = mDownloadManager.query(baseQuery
                                                   .orderBy(DownloadManager.COLUMN_TOTAL_SIZE_BYTES,
@@ -147,13 +143,10 @@ public class DownloadList extends Activity
                     mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_MEDIA_TYPE);
             mReasonColumndId =
                     mDateSortedCursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON);
-            mMediaProviderUriId =
-                    mDateSortedCursor.getColumnIndexOrThrow(
-                            DownloadManager.COLUMN_MEDIAPROVIDER_URI);
 
-            mDateSortedAdapter = new DateSortedDownloadAdapter(this, mDateSortedCursor, this);
+            mDateSortedAdapter = new DateSortedDownloadAdapter(this, mDateSortedCursor);
             mDateOrderedListView.setAdapter(mDateSortedAdapter);
-            mSizeSortedAdapter = new DownloadAdapter(this, mSizeSortedCursor, this);
+            mSizeSortedAdapter = new DownloadAdapter(this, mSizeSortedCursor);
             mSizeOrderedListView.setAdapter(mSizeSortedAdapter);
 
             ensureSomeGroupIsExpanded();
@@ -166,6 +159,7 @@ public class DownloadList extends Activity
             mIsSortedBySize = true;
         }
         chooseListToShow();
+        mSelectedCountFormat = getString(R.string.selected_count);
     }
 
     /**
@@ -189,19 +183,106 @@ public class DownloadList extends Activity
 
     private void setupViews() {
         setContentView(R.layout.download_list);
-        setTitle(getText(R.string.download_title));
 
+        //TODO don't create both views. create only the one needed.
         mDateOrderedListView = (ExpandableListView) findViewById(R.id.date_ordered_list);
-        mDateOrderedListView.setOnChildClickListener(this);
+        mDateOrderedListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+        mDateOrderedListView.setMultiChoiceModeListener(new ModalCallback(this));
+        mDateOrderedListView.setOnChildClickListener(new OnChildClickListener() {
+            // called when a child is clicked on (this is NOT the checkbox click)
+            @Override
+            public boolean onChildClick(ExpandableListView parent, View v,
+                    int groupPosition, int childPosition, long id) {
+                mDateSortedAdapter.moveCursorToChildPosition(groupPosition, childPosition);
+                handleItemClick(mDateSortedCursor);
+                return true;
+            }
+        });
         mSizeOrderedListView = (ListView) findViewById(R.id.size_ordered_list);
-        mSizeOrderedListView.setOnItemClickListener(this);
+        mSizeOrderedListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+        mSizeOrderedListView.setMultiChoiceModeListener(new ModalCallback(this));
+        mSizeOrderedListView.setOnItemClickListener(new OnItemClickListener() {
+            // handle a click from the size-sorted list. (this is NOT the checkbox click)
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                mSizeSortedCursor.moveToPosition(position);
+                handleItemClick(mSizeSortedCursor);
+            }
+        });
         mEmptyView = findViewById(R.id.empty);
+    }
+
+    private static class ModalCallback implements MultiChoiceModeListener {
+        private final DownloadList mDownloadList;
+
+        public ModalCallback(DownloadList downloadList) {
+            mDownloadList = downloadList;
+        }
+
+        @Override
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            populateMenuItems(menu);
+            return true;
+        }
 
-        mSelectionMenuView = (ViewGroup) findViewById(R.id.selection_menu);
-        mSelectionDeleteButton = (Button) findViewById(R.id.selection_delete);
-        mSelectionDeleteButton.setOnClickListener(this);
+        private void populateMenuItems(Menu menu) {
+            menu.findItem(R.id.download_menu_sort_by_size)
+                    .setVisible(!mDownloadList.mIsSortedBySize);
+            menu.findItem(R.id.download_menu_sort_by_date)
+                    .setVisible(mDownloadList.mIsSortedBySize);
+        }
 
-        ((Button) findViewById(R.id.deselect_all)).setOnClickListener(this);
+        @Override public void onDestroyActionMode(ActionMode mode) {}
+    
+        @Override
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            if (mDownloadList.haveCursors()) {
+                final MenuInflater inflater = mDownloadList.getMenuInflater();
+                inflater.inflate(R.menu.download_menu, menu);
+                populateMenuItems(menu);
+            }
+            return true;
+        }
+    
+        @Override
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            mDownloadList.handleMenuItemSelected(item);
+            int itemId = item.getItemId();
+            if (itemId == R.id.delete_download ||
+                    itemId == R.id.download_menu_sort_by_date ||
+                    itemId == R.id.download_menu_sort_by_size) {
+                // uncheck all checked items
+                ListView lv = mDownloadList.getCurrentView();
+                SparseBooleanArray checkedPositionList = lv.getCheckedItemPositions();
+                int checkedPositionListSize = checkedPositionList.size();
+                for (int i = 0; i < checkedPositionListSize; i++) {
+                    int position = checkedPositionList.keyAt(i);
+                    if (checkedPositionList.get(position, false)) {
+                        lv.setItemChecked(position, false);
+                        onItemCheckedStateChanged(mode, position, 0, false);
+                    }
+                }
+                mDownloadList.mSelectedIds.clear();
+            }
+            // update the subtitle
+            onItemCheckedStateChanged(mode, 1, 0, false);
+            // update the menu
+            populateMenuItems(mode.getMenu());
+            return true;
+        }
+    
+        @Override
+        public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
+                boolean checked) {
+            ListView lv = mDownloadList.getCurrentView();
+            int numChecked = lv.getCheckedItemCount();
+            if (numChecked > 0) {
+                mode.setTitle(String.format(mDownloadList.mSelectedCountFormat, numChecked,
+                        mDownloadList.mCurrentCursor.getCount()));
+            } else {
+                mode.setTitle("");
+            }
+        }
     }
 
     private boolean haveCursors() {
@@ -252,38 +333,26 @@ public class DownloadList extends Activity
             mSelectedIds.add(selectedId);
         }
         chooseListToShow();
-        showOrHideSelectionMenu();
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        if (haveCursors()) {
-            MenuInflater inflater = getMenuInflater();
-            inflater.inflate(R.menu.download_menu, menu);
-        }
-        return true;
-    }
-
-    @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        menu.findItem(R.id.download_menu_sort_by_size).setVisible(!mIsSortedBySize);
-        menu.findItem(R.id.download_menu_sort_by_date).setVisible(mIsSortedBySize);
-        return super.onPrepareOptionsMenu(menu);
     }
 
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
+    void handleMenuItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.download_menu_sort_by_size:
                 mIsSortedBySize = true;
                 chooseListToShow();
-                return true;
+                break;
+
             case R.id.download_menu_sort_by_date:
                 mIsSortedBySize = false;
                 chooseListToShow();
-                return true;
+                break;
+
+            case R.id.delete_download:
+                for (Long downloadId : mSelectedIds) {
+                    deleteDownload(downloadId);
+                }
+                break;
         }
-        return false;
     }
 
     /**
@@ -297,19 +366,29 @@ public class DownloadList extends Activity
             mEmptyView.setVisibility(View.VISIBLE);
         } else {
             mEmptyView.setVisibility(View.GONE);
-            activeListView().setVisibility(View.VISIBLE);
-            activeListView().invalidateViews(); // ensure checkboxes get updated
+            ListView lv = activeListView();
+            lv.setVisibility(View.VISIBLE);
+            lv.invalidateViews(); // ensure checkboxes get updated
+            invalidateOptionsMenu();
         }
+        mSelectedIds.clear();
+    }
+
+    ListView getCurrentView() {
+        return mCurrentView;
     }
 
-    /**
-     * @return the ListView that should currently be visible.
-     */
     private ListView activeListView() {
         if (mIsSortedBySize) {
-            return mSizeOrderedListView;
+            mCurrentCursor = mSizeSortedCursor;
+            mCurrentView = mSizeOrderedListView;
+            setTitle(R.string.download_title_sorted_by_size);
+        } else {
+            mCurrentCursor = mDateSortedCursor;
+            mCurrentView = mDateOrderedListView;
+            setTitle(R.string.download_title_sorted_by_date);
         }
-        return mDateOrderedListView;
+        return mCurrentView;
     }
 
     /**
@@ -378,7 +457,16 @@ public class DownloadList extends Activity
                             .setMessage(R.string.dialog_queued_body)
                             .setPositiveButton(R.string.keep_queued_download, null)
                             .setNegativeButton(R.string.remove_download, getDeleteClickHandler(id))
-                            .setOnCancelListener(this)
+                            .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                                /**
+                                 * Called when a dialog for a pending download is canceled.
+                                 */
+                                @Override
+                                public void onCancel(DialogInterface dialog) {
+                                    mQueuedDownloadId = null;
+                                    mQueuedDialog = null;
+                                }
+                            })
                             .show();
                 } else {
                     sendRunningDownloadClickedBroadcast(id);
@@ -466,97 +554,13 @@ public class DownloadList extends Activity
         sendBroadcast(intent);
     }
 
-    // handle a click from the date-sorted list
-    @Override
-    public boolean onChildClick(ExpandableListView parent, View v,
-            int groupPosition, int childPosition, long id) {
-        mDateSortedAdapter.moveCursorToChildPosition(groupPosition, childPosition);
-        handleItemClick(mDateSortedCursor);
-        return true;
-    }
-
-    // handle a click from the size-sorted list
-    @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        mSizeSortedCursor.moveToPosition(position);
-        handleItemClick(mSizeSortedCursor);
-    }
-
     // handle a click on one of the download item checkboxes
-    @Override
     public void onDownloadSelectionChanged(long downloadId, boolean isSelected) {
         if (isSelected) {
             mSelectedIds.add(downloadId);
         } else {
             mSelectedIds.remove(downloadId);
         }
-        showOrHideSelectionMenu();
-    }
-
-    private void showOrHideSelectionMenu() {
-        boolean shouldBeVisible = !mSelectedIds.isEmpty();
-        boolean isVisible = mSelectionMenuView.getVisibility() == View.VISIBLE;
-        if (shouldBeVisible) {
-            updateSelectionMenu();
-            if (!isVisible) {
-                // show menu
-                mSelectionMenuView.setVisibility(View.VISIBLE);
-                mSelectionMenuView.startAnimation(
-                        AnimationUtils.loadAnimation(this, R.anim.footer_appear));
-            }
-        } else if (!shouldBeVisible && isVisible) {
-            // hide menu
-            mSelectionMenuView.setVisibility(View.GONE);
-            mSelectionMenuView.startAnimation(
-                    AnimationUtils.loadAnimation(this, R.anim.footer_disappear));
-        }
-    }
-
-    /**
-     * Set up the contents of the selection menu based on the current selection.
-     */
-    private void updateSelectionMenu() {
-        int deleteButtonStringId = R.string.delete_download;
-        if (mSelectedIds.size() == 1) {
-            Cursor cursor = mDownloadManager.query(new DownloadManager.Query()
-                    .setFilterById(mSelectedIds.iterator().next()));
-            try {
-                cursor.moveToFirst();
-                switch (cursor.getInt(mStatusColumnId)) {
-                    case DownloadManager.STATUS_FAILED:
-                        deleteButtonStringId = R.string.delete_download;
-                        break;
-
-                    case DownloadManager.STATUS_PENDING:
-                        deleteButtonStringId = R.string.remove_download;
-                        break;
-
-                    case DownloadManager.STATUS_PAUSED:
-                    case DownloadManager.STATUS_RUNNING:
-                        deleteButtonStringId = R.string.cancel_running_download;
-                        break;
-                }
-            } finally {
-                cursor.close();
-            }
-        }
-        mSelectionDeleteButton.setText(deleteButtonStringId);
-    }
-
-    @Override
-    public void onClick(View v) {
-        switch (v.getId()) {
-            case R.id.selection_delete:
-                for (Long downloadId : mSelectedIds) {
-                    deleteDownload(downloadId);
-                }
-                clearSelection();
-                break;
-
-            case R.id.deselect_all:
-                clearSelection();
-                break;
-        }
     }
 
     /**
@@ -568,11 +572,6 @@ public class DownloadList extends Activity
         // Adapters get notification of changes and update automatically
     }
 
-    private void clearSelection() {
-        mSelectedIds.clear();
-        showOrHideSelectionMenu();
-    }
-
     /**
      * Delete a download from the Download Manager.
      */
@@ -583,7 +582,6 @@ public class DownloadList extends Activity
         mDownloadManager.markRowDeleted(downloadId);
     }
 
-    @Override
     public boolean isDownloadSelected(long id) {
         return mSelectedIds.contains(id);
     }
@@ -639,13 +637,4 @@ public class DownloadList extends Activity
         }
         return false;
     }
-
-    /**
-     * Called when a dialog for a pending download is canceled.
-     */
-    @Override
-    public void onCancel(DialogInterface dialog) {
-        mQueuedDownloadId = null;
-        mQueuedDialog = null;
-    }
 }