Add progress dialog for delete operation and make the close button work
diff --git a/res/layout/image_gallery_2.xml b/res/layout/image_gallery_2.xml
index 390a6e4..b2a9365 100644
--- a/res/layout/image_gallery_2.xml
+++ b/res/layout/image_gallery_2.xml
@@ -60,6 +60,7 @@
             android:visibility="gone"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
+            android:clickable="false"
             android:layout_alignParentBottom="true"
             android:paddingTop="5dip"
             android:paddingLeft="4dip"
@@ -67,19 +68,19 @@
             android:paddingBottom="1dip"
             android:background="@android:drawable/bottom_bar">
 
-        <Button android:id="@+id/share"
+        <Button android:id="@+id/button_share"
                 android:layout_width="0dip"
                 android:layout_height="fill_parent"
                 android:layout_weight="1"
                 android:text="@string/multiselect_share" />
 
-        <Button android:id="@+id/delete"
+        <Button android:id="@+id/button_delete"
                 android:layout_width="0dip"
                 android:layout_height="fill_parent"
                 android:layout_weight="1"
                 android:text="@string/multiselect_delete" />
 
-        <Button android:id="@+id/close"
+        <Button android:id="@+id/button_close"
                 android:layout_width="0dip"
                 android:layout_height="fill_parent"
                 android:layout_weight="1"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 70d7ff3..ebffaa1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -604,5 +604,11 @@
 
     <!-- Title shown on the button which will close the multiselction mode -->
     <string name="multiselect_close">Close</string>
+
+    <!-- The title of the progress dialog which will be shown for tasks that may take a long time -->
+    <string name="progress_dialog_title">In progress</string>
+
+    <!-- The messsage shown on progress dialog when deleting images -->
+    <string name="delete_images_message">Deleting images, please wait\u2026</string>
     
 </resources>
diff --git a/src/com/android/camera/ImageGallery.java b/src/com/android/camera/ImageGallery.java
index a0050b0..79021ae 100644
--- a/src/com/android/camera/ImageGallery.java
+++ b/src/com/android/camera/ImageGallery.java
@@ -16,6 +16,8 @@
 
 package com.android.camera;
 
+import com.android.camera.gallery.BaseCancelable;
+import com.android.camera.gallery.Cancelable;
 import com.android.camera.gallery.IImage;
 import com.android.camera.gallery.IImageList;
 import com.android.camera.gallery.VideoObject;
@@ -52,8 +54,10 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.Window;
+import android.view.View.OnClickListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
+import android.widget.Button;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -89,6 +93,8 @@
 
     GridViewSpecial mGvs;
 
+    private final PriorityTaskQueue mPriorityQueue = new PriorityTaskQueue(1);
+
     // The index of the first picture in GridViewSpecial.
     private int mSelectedIndex = GridViewSpecial.SELECT_NONE;
     private float mScrollPosition = INVALID_POSITION;
@@ -116,6 +122,10 @@
 
         mFooterOrganizeView = findViewById(R.id.footer_organize);
 
+        // consume all click events on the footer view
+        mFooterOrganizeView.setOnClickListener(Util.getNullOnClickListener());
+        initializeFooterButtons();
+
         if (isPickIntent()) {
             mVideoSizeLimit = getIntent().getLongExtra(
                     MediaStore.EXTRA_SIZE_LIMIT, Long.MAX_VALUE);
@@ -130,6 +140,26 @@
         mLoader = new ImageLoader(mHandler);
     }
 
+    private void initializeFooterButtons() {
+        Button deleteButton = (Button) findViewById(R.id.button_delete);
+        deleteButton.setOnClickListener(new OnClickListener() {
+
+            @Override
+            public void onClick(View v) {
+                onDeleteClicked();
+            }
+        });
+
+        Button closeButton = (Button) findViewById(R.id.button_close);
+        closeButton.setOnClickListener( new OnClickListener() {
+
+            @Override
+            public void onClick(View v) {
+                closeMultiSelectMode();
+            }
+        });
+    }
+
     private MenuItem addSlideShowMenu(Menu menu, int position) {
         return menu.add(0, 207, position, R.string.slide_show)
                 .setOnMenuItemClickListener(
@@ -484,12 +514,11 @@
             item.setOnMenuItemClickListener(
                     new MenuItem.OnMenuItemClickListener() {
                 public boolean onMenuItemClick(MenuItem item) {
-                    if (mMultiSelected == null) {
-                        mMultiSelected = new HashSet<IImage>();
+                    if (isInMultiSelectMode()) {
+                        closeMultiSelectMode();
                     } else {
-                        mMultiSelected = null;
+                        openMultiSelectMode();
                     }
-                    mGvs.invalidateAllImages();
                     return true;
                 }
             });
@@ -939,4 +968,53 @@
             mFooterOrganizeView.startAnimation(mFooterDisappear);
         }
     }
+
+    private void onDeleteClicked() {
+        Cancelable<Void> task = new BaseCancelable<Void>() {
+
+            @Override
+            public boolean requestCancel() {
+                return false;
+            }
+
+            @Override
+            protected Void execute() {
+                try {
+                    Thread.sleep(3000);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+                return null;
+            }
+
+        };
+        postBackgroundTask(
+                getResources().getString(R.string.delete_images_message),
+                task);
+
+    }
+
+    private <T> void postBackgroundTask(String message, Cancelable<T> task) {
+        String title = getResources().getString(R.string.progress_dialog_title);
+        PriorityTask<T> pTask = PriorityTask.wrap(task);
+        Util.showProgressDialog(this, title, message, pTask);
+        mPriorityQueue.add(pTask);
+    }
+
+    private boolean isInMultiSelectMode() {
+        return mMultiSelected != null;
+    }
+
+    private void closeMultiSelectMode() {
+        if (mMultiSelected == null) return;
+        mMultiSelected = null;
+        mGvs.invalidateAllImages();
+        hideFooter();
+    }
+
+    private void openMultiSelectMode() {
+        if (mMultiSelected != null) return;
+        mMultiSelected = new HashSet<IImage>();
+        mGvs.invalidateAllImages();
+    }
 }
diff --git a/src/com/android/camera/PriorityTask.java b/src/com/android/camera/PriorityTask.java
index a060071..82750af 100644
--- a/src/com/android/camera/PriorityTask.java
+++ b/src/com/android/camera/PriorityTask.java
@@ -81,6 +81,38 @@
         setPriority(priority);
     }
 
+    private static class CancelableAdapter<T> extends PriorityTask<T> {
+        private final Cancelable<T> mTask;
+
+        public CancelableAdapter(Cancelable<T> task, int priority) {
+            super(priority);
+            mTask = task;
+        }
+
+        @Override
+        public boolean requestCancel() {
+            if (super.requestCancel()) {
+                mTask.requestCancel();
+                return true;
+            }
+            return false;
+        }
+
+
+        @Override
+        protected T execute() throws Exception {
+            return mTask.get();
+        }
+    }
+
+    public static <T> PriorityTask<T> wrap(Cancelable<T> task, int priority) {
+        return new CancelableAdapter<T>(task, priority);
+    }
+
+    public static <T> PriorityTask<T> wrap(Cancelable<T> task) {
+        return new CancelableAdapter<T>(task, PRIORITY_DEFAULT);
+    }
+
     /**
      * Executes the task. Subclasses should override this function. Note: if
      * this function throws an <code>InterruptedException</code>, the task will
@@ -294,4 +326,4 @@
     void resetState() {
         mState = STATE_INITIAL;
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index 449319b..4991d0e 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -18,7 +18,9 @@
 
 import com.android.camera.gallery.IImage;
 
+import android.app.ProgressDialog;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -28,6 +30,8 @@
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
 
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
@@ -40,6 +44,8 @@
 public class Util {
     private static final String TAG = "db.Util";
 
+    private static OnClickListener sNullOnClickListener;
+
     private Util() {
     }
 
@@ -369,4 +375,35 @@
         }
         Log.d(tag, msg + " --- stack trace ends.");
     }
+
+    public static <T> void showProgressDialog(final Context context,
+            String title, String message, PriorityTask<T> task) {
+        final ProgressDialog dialog =
+                ProgressDialog.show(context, title, message);
+
+        task.addCallback(new PriorityTask.Callback<T>() {
+
+            public void onCanceled(PriorityTask<T> t) {
+                dialog.dismiss();
+            }
+
+            public void onFail(PriorityTask<T> t, Throwable error) {
+                dialog.dismiss();
+            }
+
+            public void onResultAvailable(PriorityTask<T> t, T result) {
+                dialog.dismiss();
+            }
+        });
+    }
+
+    public synchronized static OnClickListener getNullOnClickListener() {
+        if (sNullOnClickListener == null) {
+            sNullOnClickListener = new OnClickListener() {
+                public void onClick(View v) {
+                }
+            };
+        }
+        return sNullOnClickListener;
+    }
 }