AI 145029: Style fix.

Automated import of CL 145029
diff --git a/src/com/android/camera/ImageGallery2.java b/src/com/android/camera/ImageGallery2.java
index b9518b9..27890e3 100644
--- a/src/com/android/camera/ImageGallery2.java
+++ b/src/com/android/camera/ImageGallery2.java
@@ -16,17 +16,22 @@
 
 package com.android.camera;
 
-import android.content.BroadcastReceiver;
+import com.android.camera.gallery.IImage;
+import com.android.camera.gallery.IImageList;
+import com.android.camera.gallery.VideoObject;
+
 import android.app.Activity;
-import android.app.Dialog;
 import android.app.AlertDialog;
+import android.app.Dialog;
 import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -38,6 +43,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager;
+import android.preference.PreferenceManager;
+import android.provider.MediaStore;
 import android.util.AttributeSet;
 import android.util.Config;
 import android.util.Log;
@@ -51,27 +58,21 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.Window;
+import android.widget.Scroller;
 import android.widget.TextView;
 import android.widget.Toast;
-import android.preference.PreferenceManager;
-import android.provider.MediaStore;
-import android.widget.Scroller;
 
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 
-import com.android.camera.gallery.IImage;
-import com.android.camera.gallery.IImageList;
-import com.android.camera.gallery.VideoObject;
-
 public class ImageGallery2 extends Activity {
     private static final String TAG = "ImageGallery2";
-    private IImageList mAllImages;
+    IImageList mAllImages;
     private int mInclusion;
-    private boolean mSortAscending = false;
+    boolean mSortAscending = false;
     private View mNoImagesView;
-    public final static int CROP_MSG = 2;
-    public final static int VIEW_MSG = 3;
+    public static final int CROP_MSG = 2;
+    public static final int VIEW_MSG = 3;
     private static final String INSTANCE_STATE_TAG = "scrollY";
 
     private Dialog mMediaScanningDialog;
@@ -100,12 +101,16 @@
 
         mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
 
-        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);  // must be called before setContentView()
+        // Must be called before setContentView().
+        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
+
         setContentView(R.layout.image_gallery_2);
 
-        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_gallery_title);
-        if (Config.LOGV)
+        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
+                R.layout.custom_gallery_title);
+        if (Config.LOGV) {
             Log.v(TAG, "findView... " + findViewById(R.id.loading_indicator));
+        }
 
         mGvs = (GridViewSpecial) findViewById(R.id.grid);
         mGvs.requestFocus();
@@ -117,82 +122,45 @@
         } else {
             mVideoSizeLimit = Long.MAX_VALUE;
             mGvs.mVideoSizeLimit = mVideoSizeLimit;
-            mGvs.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
-                public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
-                    if (mSelectedImageGetter.getCurrentImage() == null)
-                        return;
-
-                    boolean isImage = ImageManager.isImage(mSelectedImageGetter.getCurrentImage());
-                    if (isImage) {
-                        menu.add(0, 0, 0, R.string.view).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                            public boolean onMenuItemClick(MenuItem item) {
-                                mGvs.onSelect(mGvs.mCurrentSelection);
-                                return true;
-                            }
-                        });
-                    }
-
-                    menu.setHeaderTitle(isImage ? R.string.context_menu_header
-                            : R.string.video_context_menu_header);
-                    if ((mInclusion & (ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS)) != 0) {
-                        MenuHelper.MenuItemsResult r = MenuHelper.addImageMenuItems(
-                                menu,
-                                MenuHelper.INCLUDE_ALL,
-                                isImage,
-                                ImageGallery2.this,
-                                mHandler,
-                                mDeletePhotoRunnable,
-                                new MenuHelper.MenuInvoker() {
-                                    public void run(MenuHelper.MenuCallback cb) {
-                                        cb.run(mSelectedImageGetter.getCurrentImageUri(), mSelectedImageGetter.getCurrentImage());
-
-                                        mGvs.clearCache();
-                                        mGvs.invalidate();
-                                        mGvs.requestLayout();
-                                        mGvs.start();
-                                        mNoImagesView.setVisibility(mAllImages.getCount() > 0 ? View.GONE : View.VISIBLE);
-                                    }
-                                });
-                        if (r != null)
-                            r.gettingReadyToOpen(menu, mSelectedImageGetter.getCurrentImage());
-
-                        if (isImage) {
-                            addSlideShowMenu(menu, 1000);
-                        }
-                    }
-                }
-            });
+            mGvs.setOnCreateContextMenuListener(
+                    new CreateContextMenuListener());
         }
     }
 
     private MenuItem addSlideShowMenu(Menu menu, int position) {
         return menu.add(0, 207, position, R.string.slide_show)
-        .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-            public boolean onMenuItemClick(MenuItem item) {
-                IImage img = mSelectedImageGetter.getCurrentImage();
-                if (img == null) {
-                    img = mAllImages.getImageAt(0);
-                    if (img == null) {
-                        return true;
+                .setOnMenuItemClickListener(
+                new MenuItem.OnMenuItemClickListener() {
+                    public boolean onMenuItemClick(MenuItem item) {
+                        return onSlideShowClicked();
                     }
-                }
-                Uri targetUri = img.fullSizeImageUri();
-                Uri thisUri = getIntent().getData();
-                if (thisUri != null) {
-                    String bucket = thisUri.getQueryParameter("bucketId");
-                    if (bucket != null) {
-                        targetUri = targetUri.buildUpon().appendQueryParameter("bucketId", bucket).build();
-                    }
-                }
-                Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
-                intent.putExtra("slideshow", true);
-                startActivity(intent);
-                return true;
-            }
-        })
-        .setIcon(android.R.drawable.ic_menu_slideshow);
+                }).setIcon(android.R.drawable.ic_menu_slideshow);
     }
 
+    public boolean onSlideShowClicked() {
+        IImage img = mSelectedImageGetter.getCurrentImage();
+        if (img == null) {
+            img = mAllImages.getImageAt(0);
+            if (img == null) {
+                return true;
+            }
+        }
+        Uri targetUri = img.fullSizeImageUri();
+        Uri thisUri = getIntent().getData();
+        if (thisUri != null) {
+            String bucket = thisUri.getQueryParameter("bucketId");
+            if (bucket != null) {
+                targetUri = targetUri.buildUpon()
+                        .appendQueryParameter("bucketId", bucket)
+                        .build();
+            }
+        }
+        Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
+        intent.putExtra("slideshow", true);
+        startActivity(intent);
+        return true;
+    }
+    
     private Runnable mDeletePhotoRunnable = new Runnable() {
         public void run() {
             mGvs.clearCache();
@@ -203,29 +171,35 @@
             mGvs.invalidate();
             mGvs.requestLayout();
             mGvs.start();
-            mNoImagesView.setVisibility(mAllImages.isEmpty() ? View.VISIBLE : View.GONE);
+            mNoImagesView.setVisibility(mAllImages.isEmpty()
+                    ? View.VISIBLE
+                    : View.GONE);
         }
     };
 
-    private SelectedImageGetter mSelectedImageGetter = new SelectedImageGetter() {
-        public Uri getCurrentImageUri() {
-            IImage image = getCurrentImage();
-            if (image != null)
-                return image.fullSizeImageUri();
-            else
-                return null;
-        }
-        public IImage getCurrentImage() {
-            int currentSelection = mGvs.mCurrentSelection;
-            if (currentSelection < 0 || currentSelection >= mAllImages.getCount())
-                return null;
-            else
-                return mAllImages.getImageAt(currentSelection);
-        }
-    };
+    private SelectedImageGetter mSelectedImageGetter =
+            new SelectedImageGetter() {
+                public Uri getCurrentImageUri() {
+                    IImage image = getCurrentImage();
+                    if (image != null) {
+                        return image.fullSizeImageUri();
+                    } else {
+                        return null;
+                    }
+                }
+                public IImage getCurrentImage() {
+                    int currentSelection = mGvs.mCurrentSelection;
+                    if (currentSelection < 0
+                            || currentSelection >= mAllImages.getCount()) {
+                        return null;
+                    } else {
+                        return mAllImages.getImageAt(currentSelection);
+                    }
+                }
+            };
 
     @Override
-    public void onConfigurationChanged(android.content.res.Configuration newConfig) {
+    public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         mTargetScroll = mGvs.getScrollY();
     }
@@ -237,19 +211,21 @@
         }
     };
 
-    private boolean canHandleEvent() {
+    boolean canHandleEvent() {
         // Don't process event in pause state.
         return (!mPausing) && (mGvs.mCurrentSpec != null);
     }
     
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (!canHandleEvent())  return false;
+        if (!canHandleEvent()) return false;
         
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             mGvs.select(-2, false);
-            // The keyUp doesn't get called when the longpress menu comes up. We only get here when the user
-            // lets go of the center key before the longpress menu comes up.
+            
+            // The keyUp doesn't get called when the longpress menu comes up. We
+            // only get here when the user lets go of the center key before the
+            // longpress menu comes up.
             mHandler.removeCallbacks(mLongPressCallback);
 
             // open the photo
@@ -263,7 +239,7 @@
     
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (!canHandleEvent())  return false;
+        if (!canHandleEvent()) return false;
         
         boolean handled = true;
         int sel = mGvs.mCurrentSelection;
@@ -288,13 +264,14 @@
                     }
                     break;
                 case KeyEvent.KEYCODE_DPAD_DOWN:
-                    if ((sel / columns) != (sel+columns / columns)) {
-                        sel = Math.min(count-1, sel + columns);
+                    if ((sel / columns) != (sel + columns / columns)) {
+                        sel = Math.min(count - 1, sel + columns);
                     }
                     break;
                 case KeyEvent.KEYCODE_DPAD_CENTER:
                     pressed = true;
-                    mHandler.postDelayed(mLongPressCallback, ViewConfiguration.getLongPressTimeout());
+                    mHandler.postDelayed(mLongPressCallback,
+                            ViewConfiguration.getLongPressTimeout());
                     break;
                 case KeyEvent.KEYCODE_DEL:
                     MenuHelper.deleteImage(this, mDeletePhotoRunnable,
@@ -306,41 +283,45 @@
             }
         } else {
             switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-                int [] range = new int[2];
-                GridViewSpecial.ImageBlockManager ibm = mGvs.mImageBlockManager;
-                if (ibm != null) {
-                    mGvs.mImageBlockManager.getVisibleRange(range);
-                    int topPos = range[0];
-                    android.graphics.Rect r = mGvs.getRectForPosition(topPos);
-                    if (r.top < mGvs.getScrollY())
-                        topPos += columns;
-                    topPos = Math.min(count - 1, topPos);
-                    sel = topPos;
-                }
-                break;
-            default:
-                handled = false;
-                break;
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                case KeyEvent.KEYCODE_DPAD_UP:
+                case KeyEvent.KEYCODE_DPAD_DOWN:
+                    int [] range = new int[2];
+                    GridViewSpecial.ImageBlockManager ibm =
+                            mGvs.mImageBlockManager;
+                    if (ibm != null) {
+                        mGvs.mImageBlockManager.getVisibleRange(range);
+                        int topPos = range[0];
+                        android.graphics.Rect r =
+                                mGvs.getRectForPosition(topPos);
+                        if (r.top < mGvs.getScrollY()) {
+                            topPos += columns;
+                        }
+                        topPos = Math.min(count - 1, topPos);
+                        sel = topPos;
+                    }
+                    break;
+                default:
+                    handled = false;
+                    break;
             }
         }
         if (handled) {
             mGvs.select(sel, pressed);
             return true;
-        }
-        else
+        } else {
             return super.onKeyDown(keyCode, event);
+        }
     }
 
-    private boolean isPickIntent() {
+    boolean isPickIntent() {
         String action = getIntent().getAction();
-        return (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action));
+        return (Intent.ACTION_PICK.equals(action)
+                || Intent.ACTION_GET_CONTENT.equals(action));
     }
 
-    private void launchCropperOrFinish(IImage img) {
+    void launchCropperOrFinish(IImage img) {
         Bundle myExtras = getIntent().getExtras();
 
         long size = MenuHelper.getImageFileSize(img);
@@ -369,8 +350,9 @@
         String cropValue = myExtras != null ? myExtras.getString("crop") : null;
         if (cropValue != null) {
             Bundle newExtras = new Bundle();
-            if (cropValue.equals("circle"))
+            if (cropValue.equals("circle")) {
                 newExtras.putString("circleCrop", "true");
+            }
 
             Intent cropIntent = new Intent();
             cropIntent.setData(img.fullSizeImageUri());
@@ -385,8 +367,9 @@
             Intent result = new Intent(null, img.fullSizeImageUri());
             if (myExtras != null && myExtras.getString("return-data") != null) {
                 Bitmap bitmap = img.fullSizeBitmap(1000);
-                if (bitmap != null)
+                if (bitmap != null) {
                     result.putExtra("data", bitmap);
+                }
             }
             setResult(RESULT_OK, result);
             finish();
@@ -394,18 +377,22 @@
     }
 
     @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (Config.LOGV)
-            Log.v(TAG, "onActivityResult: " + requestCode + "; resultCode is " + resultCode + "; data is " + data);
+    protected void onActivityResult(int requestCode, int resultCode,
+            Intent data) {
+        if (Config.LOGV) {
+            Log.v(TAG, "onActivityResult: " + requestCode
+                    + "; resultCode is " + resultCode + "; data is " + data);
+        }
         switch (requestCode) {
             case MenuHelper.RESULT_COMMON_MENU_CROP: {
                 if (resultCode == RESULT_OK) {
-                    // The CropImage activity passes back the Uri of the cropped image as
-                    // the Action rather than the Data.
+
+                    // The CropImage activity passes back the Uri of the cropped
+                    // image as the Action rather than the Data.
                     Uri dataUri = Uri.parse(data.getAction());
-                    rebake(false,false);
+                    rebake(false, false);
                     IImage image = mAllImages.getImageForUri(dataUri);
-                    if (image != null ) {
+                    if (image != null) {
                         int rowId = image.getRow();
                         mGvs.select(rowId, false);
                     }
@@ -421,8 +408,9 @@
                 break;
             }
             case VIEW_MSG: {
-                if (Config.LOGV)
+                if (Config.LOGV) {
                     Log.v(TAG, "got VIEW_MSG with " + data);
+                }
                 IImage img = mAllImages.getImageForUri(data.getData());
                 launchCropperOrFinish(img);
                 break;
@@ -441,8 +429,9 @@
             unregisterReceiver(mReceiver);
             mReceiver = null;
         }
-        // Now that we've paused the threads that are using the cursor it is safe
-        // to deactivate it.
+
+        // Now that we've paused the threads that are using the cursor it is
+        // safe to deactivate it.
         mAllImages.deactivate();
     }
 
@@ -467,8 +456,9 @@
             mAllImages = ImageManager.instance().emptyImageList();
         } else {
             mAllImages = allImages(!unmounted);
-            if (Config.LOGV)
+            if (Config.LOGV) {
                 Log.v(TAG, "mAllImages is now " + mAllImages);
+            }
             mGvs.init(mHandler);
             mGvs.start();
             mGvs.requestLayout();
@@ -496,19 +486,21 @@
         super.onResume();
 
         try {
-            mGvs.setSizeChoice(Integer.parseInt(mPrefs.getString("pref_gallery_size_key", "1")), mTargetScroll);
+            mGvs.setSizeChoice(Integer.parseInt(
+                    mPrefs.getString("pref_gallery_size_key", "1")),
+                    mTargetScroll);
 
             String sortOrder = mPrefs.getString("pref_gallery_sort_key", null);
             if (sortOrder != null) {
                 mSortAscending = sortOrder.equals("ascending");
             }
-        } catch (Exception ex) {
-
+        } catch (RuntimeException ex) {
         }
         mPausing = false;
 
         // install an intent filter to receive SD card related events.
-        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
+        IntentFilter intentFilter =
+                new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
         intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
         intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
         intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
@@ -518,7 +510,9 @@
         mReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                if (Config.LOGV) Log.v(TAG, "onReceiveIntent " + intent.getAction());
+                if (Config.LOGV) {
+                    Log.v(TAG, "onReceiveIntent " + intent.getAction());
+                }
                 String action = intent.getAction();
                 if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
                     // SD card available
@@ -527,18 +521,24 @@
                 } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
                     // SD card unavailable
                     if (Config.LOGV) Log.v(TAG, "sd card no longer available");
-                    Toast.makeText(ImageGallery2.this, getResources().getString(R.string.wait), 5000);
+                    Toast.makeText(ImageGallery2.this,
+                            getResources().getString(R.string.wait), 5000);
                     rebake(true, false);
                 } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
-                    Toast.makeText(ImageGallery2.this, getResources().getString(R.string.wait), 5000);
+                    Toast.makeText(ImageGallery2.this,
+                            getResources().getString(R.string.wait), 5000);
                     rebake(false, true);
-                } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
-                    if (Config.LOGV)
-                        Log.v(TAG, "rebake because of ACTION_MEDIA_SCANNER_FINISHED");
+                } else if (action.equals(
+                        Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
+                    if (Config.LOGV) {
+                        Log.v(TAG, "rebake because of "
+                                + "ACTION_MEDIA_SCANNER_FINISHED");
+                    }
                     rebake(false, false);
                 } else if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
-                    if (Config.LOGV)
+                    if (Config.LOGV) {
                         Log.v(TAG, "rebake because of ACTION_MEDIA_EJECT");
+                    }
                     rebake(true, false);
                 }
             }
@@ -564,60 +564,74 @@
         mThumbnailCheckThread = new CameraThread(new Runnable() {
             public void run() {
                 android.content.res.Resources resources = getResources();
-                final TextView progressTextView = (TextView) findViewById(R.id.loading_text);
-                final String progressTextFormatString = resources.getString(R.string.loading_progress_format_string);
+                final TextView progressTextView =
+                        (TextView) findViewById(R.id.loading_text);
+                final String progressTextFormatString =
+                        resources.getString(
+                        R.string.loading_progress_format_string);
 
-                PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
+                PowerManager pm =
+                        (PowerManager) getSystemService(Context.POWER_SERVICE);
                 PowerManager.WakeLock mWakeLock =
                     pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                                    "ImageGallery2.checkThumbnails");
                 mWakeLock.acquire();
-                IImageList.ThumbCheckCallback r = new IImageList.ThumbCheckCallback() {
-                    boolean mDidSetProgress = false;
+                IImageList.ThumbCheckCallback r =
+                        new IImageList.ThumbCheckCallback() {
+                            boolean mDidSetProgress = false;
 
-                    public boolean checking(final int count, final int maxCount) {
-                        if (mStopThumbnailChecking) {
-                            return false;
-                        }
-
-                        if (!mLayoutComplete) {
-                            return true;
-                        }
-
-                        if (!mDidSetProgress) {
-                            mHandler.post(new Runnable() {
-                                public void run() {
-                                    findViewById(R.id.loading_indicator).setVisibility(View.VISIBLE);
+                            public boolean checking(final int count,
+                                    final int maxCount) {
+                                if (mStopThumbnailChecking) {
+                                    return false;
                                 }
-                            });
-                            mDidSetProgress = true;
-                        }
-                        mGvs.postInvalidate();
 
-                        if (System.currentTimeMillis() - startTime > 1000) {
-                            mHandler.post(new Runnable() {
-                                public void run() {
-                                    String s = String.format(progressTextFormatString, maxCount - count);
-                                    progressTextView.setText(s);
+                                if (!mLayoutComplete) {
+                                    return true;
                                 }
-                            });
-                        }
 
-                        return !mPausing;
-                    }
-                };
+                                if (!mDidSetProgress) {
+                                    mHandler.post(new Runnable() {
+                                        public void run() {
+                                                findViewById(
+                                                R.id.loading_indicator)
+                                                .setVisibility(View.VISIBLE);
+                                        }
+                                    });
+                                    mDidSetProgress = true;
+                                }
+                                mGvs.postInvalidate();
+
+                                if (System.currentTimeMillis()
+                                        - startTime > 1000) {
+                                    mHandler.post(new Runnable() {
+                                        public void run() {
+                                            String s = String.format(
+                                                    progressTextFormatString,
+                                                    maxCount - count);
+                                            progressTextView.setText(s);
+                                        }
+                                    });
+                                }
+
+                                return !mPausing;
+                            }
+                        };
                 IImageList imageList = allImages(true);
                 imageList.checkThumbnails(r, imageList.getCount());
                 mWakeLock.release();
                 mThumbnailCheckThread = null;
                 mHandler.post(new Runnable() {
                     public void run() {
-                        findViewById(R.id.loading_indicator).setVisibility(View.GONE);
+                        findViewById(R.id.loading_indicator).setVisibility(
+                                View.GONE);
                     }
                 });
                 long t2 = System.currentTimeMillis();
-                if (Config.LOGV)
-                    Log.v(TAG, "check thumbnails thread finishing; took " + (t2-t1));
+                if (Config.LOGV) {
+                    Log.v(TAG, "check thumbnails thread finishing; took "
+                            + (t2 - t1));
+                }
             }
         });
 
@@ -626,7 +640,9 @@
         mThumbnailCheckThread.toBackground();
 
         IImageList list = allImages(true);
-        mNoImagesView.setVisibility(list.getCount() > 0 ? View.GONE : View.VISIBLE);
+        mNoImagesView.setVisibility(list.getCount() > 0
+                ? View.GONE
+                : View.VISIBLE);
     }
 
     @Override
@@ -660,7 +676,8 @@
     public boolean onPrepareOptionsMenu(android.view.Menu menu) {
         if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) {
             boolean videoSelected = isVideoSelected();
-            // TODO: Only enable slide show if there is at least one image in the folder.
+            // TODO: Only enable slide show if there is at least one image in
+            // the folder.
             if (mSlideShowItem != null) {
                 mSlideShowItem.setEnabled(!videoSelected);
             }
@@ -683,39 +700,50 @@
         if (mAllImages == null) {
             mNoImagesView = findViewById(R.id.no_images);
 
-            mInclusion = ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS;
+            mInclusion = ImageManager.INCLUDE_IMAGES
+                    | ImageManager.INCLUDE_VIDEOS;
 
             Intent intent = getIntent();
             if (intent != null) {
                 String type = intent.resolveType(this);
-                if (Config.LOGV)
+                if (Config.LOGV) {
                     Log.v(TAG, "allImages... type is " + type);
+                }
                 TextView leftText = (TextView) findViewById(R.id.left_text);
                 if (type != null) {
-                    if (type.equals("vnd.android.cursor.dir/image") || type.equals("image/*")) {
+                    if (type.equals("vnd.android.cursor.dir/image")
+                            || type.equals("image/*")) {
                         mInclusion = ImageManager.INCLUDE_IMAGES;
-                        if (isPickIntent())
-                            leftText.setText(R.string.pick_photos_gallery_title);
-                        else
+                        if (isPickIntent()) {
+                            leftText.setText(
+                                    R.string.pick_photos_gallery_title);
+                        } else {
                             leftText.setText(R.string.photos_gallery_title);
+                        }
                     }
-                    if (type.equals("vnd.android.cursor.dir/video") || type.equals("video/*")) {
+                    if (type.equals("vnd.android.cursor.dir/video")
+                            || type.equals("video/*")) {
                         mInclusion = ImageManager.INCLUDE_VIDEOS;
-                        if (isPickIntent())
-                            leftText.setText(R.string.pick_videos_gallery_title);
-                        else
+                        if (isPickIntent()) {
+                            leftText.setText(
+                                    R.string.pick_videos_gallery_title);
+                        } else {
                             leftText.setText(R.string.videos_gallery_title);
+                        }
                     }
                 }
                 Bundle extras = intent.getExtras();
-                String title = extras!= null ? extras.getString("windowTitle") : null;
+                String title = (extras != null)
+                        ? extras.getString("windowTitle")
+                        : null;
                 if (title != null && title.length() > 0) {
                     leftText.setText(title);
                 }
 
                 if (extras != null) {
-                    mInclusion = (ImageManager.INCLUDE_IMAGES | ImageManager.INCLUDE_VIDEOS)
-                        & extras.getInt("mediaTypes", mInclusion);
+                    mInclusion = (ImageManager.INCLUDE_IMAGES
+                            | ImageManager.INCLUDE_VIDEOS)
+                            & extras.getInt("mediaTypes", mInclusion);
                 }
 
                 if (extras != null && extras.getBoolean("pick-drm")) {
@@ -723,9 +751,11 @@
                     mInclusion = ImageManager.INCLUDE_DRM_IMAGES;
                 }
             }
-            if (Config.LOGV)
-                Log.v(TAG, "computing images... mSortAscending is " + mSortAscending
-                        + "; assumeMounted is " + assumeMounted);
+            if (Config.LOGV) {
+                Log.v(TAG, "computing images... mSortAscending is "
+                        + mSortAscending + "; assumeMounted is "
+                        + assumeMounted);
+            }
             Uri uri = getIntent().getData();
             if (!assumeMounted) {
                 mAllImages = ImageManager.instance().emptyImageList();
@@ -735,1130 +765,1336 @@
                         getContentResolver(),
                         ImageManager.DataLocation.NONE,
                         mInclusion,
-                        mSortAscending ? ImageManager.SORT_ASCENDING : ImageManager.SORT_DESCENDING,
-                        uri != null ? uri.getQueryParameter("bucketId") : null);
+                        mSortAscending
+                        ? ImageManager.SORT_ASCENDING
+                        : ImageManager.SORT_DESCENDING,
+                        (uri != null)
+                        ? uri.getQueryParameter("bucketId")
+                        : null);
             }
         }
         return mAllImages;
     }
 
-    public static class GridViewSpecial extends View {
-        private ImageGallery2 mGallery;
-        private Paint   mGridViewPaint = new Paint();
-
-        private ImageBlockManager mImageBlockManager;
-        private Handler mHandler;
-
-        private LayoutSpec mCurrentSpec;
-        private boolean mShowSelection = false;
-        private int mCurrentSelection = -1;
-        private boolean mCurrentSelectionPressed;
-
-        private boolean mDirectionBiasDown = true;
-        private final static boolean sDump = false;
-
-        private long mVideoSizeLimit;
-
-        class LayoutSpec {
-            LayoutSpec(int cols, int w, int h, int leftEdgePadding, int rightEdgePadding, int intercellSpacing) {
-                mColumns = cols;
-                mCellWidth = w;
-                mCellHeight = h;
-                mLeftEdgePadding = leftEdgePadding;
-                mRightEdgePadding = rightEdgePadding;
-                mCellSpacing = intercellSpacing;
+    private class CreateContextMenuListener implements
+            View.OnCreateContextMenuListener {
+        public void onCreateContextMenu(ContextMenu menu, View v,
+                ContextMenu.ContextMenuInfo menuInfo) {
+            if (mSelectedImageGetter.getCurrentImage() == null) {
+                return;
             }
-            int mColumns;
-            int mCellWidth, mCellHeight;
-            int mLeftEdgePadding, mRightEdgePadding;
-            int mCellSpacing;
-        };
 
-        private LayoutSpec [] mCellSizeChoices = new LayoutSpec[] {
-                new LayoutSpec(0, 67, 67, 14, 14, 8),
-                new LayoutSpec(0, 92, 92, 14, 14, 8),
-        };
-        private int mSizeChoice = 1;
-
-        // Use a number like 100 or 200 here to allow the user to
-        // overshoot the start (top) or end (bottom) of the gallery.
-        // After overshooting the gallery will animate back to the
-        // appropriate location.
-        private int mMaxOvershoot = 0; // 100;
-        private int mMaxScrollY;
-        private int mMinScrollY;
-
-        private boolean mFling = true;
-        private Scroller mScroller = null;
-
-        private GestureDetector mGestureDetector;
-
-        public void dump() {
-            if (Config.LOGV){
-                Log.v(TAG, "mSizeChoice is " + mCellSizeChoices[mSizeChoice]);
-                Log.v(TAG, "mCurrentSpec.width / mCellHeight are " + mCurrentSpec.mCellWidth + " / " + mCurrentSpec.mCellHeight);
+            boolean isImage = ImageManager.isImage(
+                    mSelectedImageGetter.getCurrentImage());
+            if (isImage) {
+                menu.add(0, 0, 0, R.string.view).setOnMenuItemClickListener(
+                        new MenuItem.OnMenuItemClickListener() {
+                            public boolean onMenuItemClick(MenuItem item) {
+                                mGvs.onSelect(mGvs.mCurrentSelection);
+                                return true;
+                            }
+                        });
             }
-            mImageBlockManager.dump();
+
+            menu.setHeaderTitle(isImage
+                    ? R.string.context_menu_header
+                    : R.string.video_context_menu_header);
+            if ((mInclusion & (ImageManager.INCLUDE_IMAGES
+                    | ImageManager.INCLUDE_VIDEOS)) != 0) {
+                MenuHelper.MenuItemsResult r = MenuHelper.addImageMenuItems(
+                        menu,
+                        MenuHelper.INCLUDE_ALL,
+                        isImage,
+                        ImageGallery2.this,
+                        mHandler,
+                        mDeletePhotoRunnable,
+                        new MenuHelper.MenuInvoker() {
+                            public void run(MenuHelper.MenuCallback cb) {
+                                cb.run(mSelectedImageGetter
+                                        .getCurrentImageUri(),
+                                        mSelectedImageGetter.getCurrentImage());
+
+                                mGvs.clearCache();
+                                mGvs.invalidate();
+                                mGvs.requestLayout();
+                                mGvs.start();
+                                mNoImagesView.setVisibility(
+                                        mAllImages.getCount() > 0
+                                        ? View.GONE
+                                        : View.VISIBLE);
+                            }
+                        });
+                if (r != null) {
+                    r.gettingReadyToOpen(menu,
+                            mSelectedImageGetter.getCurrentImage());
+                }
+
+                if (isImage) {
+                    addSlideShowMenu(menu, 1000);
+                }
+            }
         }
+    }
+}
 
-        private void init(Context context) {
-            mGridViewPaint.setColor(0xFF000000);
-            mGallery = (ImageGallery2) context;
 
-            setVerticalScrollBarEnabled(true);
-            initializeScrollbars(context.obtainStyledAttributes(android.R.styleable.View));
+class GridViewSpecial extends View {
+    private static final String TAG = "GridViewSpecial";
+    ImageGallery2 mGallery;
+    private Paint   mGridViewPaint = new Paint();
 
-            mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {
-                @Override
-                public boolean onDown(MotionEvent e) {
-                    if (mScroller != null && !mScroller.isFinished()) {
-                        mScroller.forceFinished(true);
-                        return false;
-                    }
+    ImageBlockManager mImageBlockManager;
+    private Handler mHandler;
 
-                    int pos = computeSelectedIndex(e);
-                    if (pos >= 0 && pos < mGallery.mAllImages.getCount()) {
-                        select(pos, true);
-                    } else {
-                        select(-1, false);
-                    }
-                    if (mImageBlockManager != null)
-                        mImageBlockManager.repaintSelection(mCurrentSelection);
-                    invalidate();
-                    return true;
-                }
+    LayoutSpec mCurrentSpec;
+    boolean mShowSelection = false;
+    int mCurrentSelection = -1;
+    private boolean mCurrentSelectionPressed;
 
-                @Override
-                public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
-                    final float maxVelocity = 2500;
-                    if (velocityY > maxVelocity)
-                        velocityY = maxVelocity;
-                    else if (velocityY < -maxVelocity)
-                        velocityY = -maxVelocity;
+    private boolean mDirectionBiasDown = true;
+    private static final boolean DUMP = false;
 
-                    select(-1, false);
-                    if (mFling) {
-                        mScroller = new Scroller(getContext());
-                        mScroller.fling(0, mScrollY, 0, -(int)velocityY, 0, 0, 0, mMaxScrollY);
-                        computeScroll();
-                    }
-                    return true;
-                }
+    long mVideoSizeLimit;
 
-                @Override
-                public void onLongPress(MotionEvent e) {
-                    performLongClick();
-                }
+    class LayoutSpec {
+        LayoutSpec(int cols, int w, int h, int leftEdgePadding,
+                   int rightEdgePadding, int intercellSpacing) {
+            mColumns = cols;
+            mCellWidth = w;
+            mCellHeight = h;
+            mLeftEdgePadding = leftEdgePadding;
+            mRightEdgePadding = rightEdgePadding;
+            mCellSpacing = intercellSpacing;
+        }
+        int mColumns;
+        int mCellWidth, mCellHeight;
+        int mLeftEdgePadding, mRightEdgePadding;
+        int mCellSpacing;
+    };
 
-                @Override
-                public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
-                    select(-1, false);
-                    scrollBy(0, (int)distanceY);
-                    invalidate();
-                    return true;
-                }
+    private LayoutSpec [] mCellSizeChoices = new LayoutSpec[] {
+            new LayoutSpec(0, 67, 67, 14, 14, 8),
+            new LayoutSpec(0, 92, 92, 14, 14, 8),
+    };
+    private int mSizeChoice = 1;
 
-                @Override
-                public boolean onSingleTapUp(MotionEvent e) {
-                    select(mCurrentSelection, false);
-                    int index = computeSelectedIndex(e);
-                    if (index >= 0 && index < mGallery.mAllImages.getCount()) {
-                        onSelect(index);
-                        return true;
-                    }
+    // Use a number like 100 or 200 here to allow the user to
+    // overshoot the start (top) or end (bottom) of the gallery.
+    // After overshooting the gallery will animate back to the
+    // appropriate location.
+    private int mMaxOvershoot = 0; // 100;
+    private int mMaxScrollY;
+    private int mMinScrollY;
+
+    private boolean mFling = true;
+    private Scroller mScroller = null;
+
+    private GestureDetector mGestureDetector;
+
+    public void dump() {
+        if (Config.LOGV){
+            Log.v(TAG, "mSizeChoice is " + mCellSizeChoices[mSizeChoice]);
+            Log.v(TAG, "mCurrentSpec.width / mCellHeight are "
+                    + mCurrentSpec.mCellWidth + " / "
+                    + mCurrentSpec.mCellHeight);
+        }
+        mImageBlockManager.dump();
+    }
+
+    private void init(Context context) {
+        mGridViewPaint.setColor(0xFF000000);
+        mGallery = (ImageGallery2) context;
+
+        setVerticalScrollBarEnabled(true);
+        initializeScrollbars(context.obtainStyledAttributes(
+                android.R.styleable.View));
+
+        mGestureDetector = new GestureDetector(context,
+                new SimpleOnGestureListener() {
+            @Override
+            public boolean onDown(MotionEvent e) {
+                if (mScroller != null && !mScroller.isFinished()) {
+                    mScroller.forceFinished(true);
                     return false;
                 }
-            });
-//          mGestureDetector.setIsLongpressEnabled(false);
-        }
 
-        public GridViewSpecial(Context context, AttributeSet attrs, int defStyle) {
-            super(context, attrs, defStyle);
-            init(context);
-        }
-
-        public GridViewSpecial(Context context, AttributeSet attrs) {
-            super(context, attrs);
-            init(context);
-        }
-
-        public GridViewSpecial(Context context) {
-            super(context);
-            init(context);
-        }
-
-        @Override
-        protected int computeVerticalScrollRange() {
-            return mMaxScrollY + getHeight();
-        }
-
-        public void setSizeChoice(int choice, int scrollY) {
-            mSizeChoice = choice;
-            clearCache();
-            scrollTo(0, scrollY);
-            requestLayout();
-            invalidate();
-        }
-
-        /**
-         *
-         * @param newSel -2 means use old selection, -1 means remove selection
-         * @param newPressed
-         */
-        public void select(int newSel, boolean newPressed) {
-            if (newSel == -2) {
-                newSel = mCurrentSelection;
-            }
-            int oldSel = mCurrentSelection;
-            if ((oldSel == newSel) && (mCurrentSelectionPressed == newPressed))
-                return;
-
-            mShowSelection = (newSel != -1);
-            mCurrentSelection = newSel;
-            mCurrentSelectionPressed = newPressed;
-            if (mImageBlockManager != null) {
-                mImageBlockManager.repaintSelection(oldSel);
-                mImageBlockManager.repaintSelection(newSel);
-            }
-
-            if (newSel != -1)
-                ensureVisible(newSel);
-        }
-
-        private void ensureVisible(int pos) {
-            android.graphics.Rect r = getRectForPosition(pos);
-            int top = getScrollY();
-            int bot = top + getHeight();
-
-            if (r.bottom > bot) {
-                mScroller = new Scroller(getContext());
-                mScroller.startScroll(mScrollX, mScrollY, 0, r.bottom - getHeight() - mScrollY, 200);
-                computeScroll();
-            } else if (r.top < top) {
-                mScroller = new Scroller(getContext());
-                mScroller.startScroll(mScrollX, mScrollY, 0, r.top - mScrollY, 200);
-                computeScroll();
-            }
-            invalidate();
-        }
-
-        public void start() {
-            if (mGallery.mLayoutComplete) {
-                if (mImageBlockManager == null) {
-                    mImageBlockManager = new ImageBlockManager();
-                    mImageBlockManager.moveDataWindow(true, true);
-                }
-            }
-        }
-
-        public void onPause() {
-            mScroller = null;
-            if (mImageBlockManager != null) {
-                mImageBlockManager.onPause();
-                mImageBlockManager = null;
-            }
-        }
-
-        public void clearCache() {
-            if (mImageBlockManager != null) {
-                mImageBlockManager.onPause();
-                mImageBlockManager = null;
-            }
-        }
-
-
-        @Override
-        public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-            super.onLayout(changed, left, top, right, bottom);
-
-            if (mGallery.isFinishing() || mGallery.mPausing) {
-                return;
-            }
-
-            clearCache();
-
-            mCurrentSpec = mCellSizeChoices[mSizeChoice];
-            int oldColumnCount = mCurrentSpec.mColumns;
-
-            int width = right - left;
-            mCurrentSpec.mColumns = 1;
-            width -= mCurrentSpec.mCellWidth;
-            mCurrentSpec.mColumns += width / (mCurrentSpec.mCellWidth + mCurrentSpec.mCellSpacing);
-
-            mCurrentSpec.mLeftEdgePadding = ((right - left) - ((mCurrentSpec.mColumns - 1) * mCurrentSpec.mCellSpacing) - (mCurrentSpec.mColumns * mCurrentSpec.mCellWidth)) / 2;
-            mCurrentSpec.mRightEdgePadding = mCurrentSpec.mLeftEdgePadding;
-
-            int rows = (mGallery.mAllImages.getCount() + mCurrentSpec.mColumns - 1) / mCurrentSpec.mColumns;
-            mMaxScrollY = mCurrentSpec.mCellSpacing + (rows * (mCurrentSpec.mCellSpacing + mCurrentSpec.mCellHeight)) - (bottom - top) + mMaxOvershoot;
-            mMinScrollY = 0 - mMaxOvershoot;
-
-            mGallery.mLayoutComplete = true;
-
-            start();
-
-            if (mGallery.mSortAscending && mGallery.mTargetScroll == 0) {
-                scrollTo(0, mMaxScrollY - mMaxOvershoot);
-            } else {
-                if (oldColumnCount != 0) {
-                    int y = mGallery.mTargetScroll * oldColumnCount / mCurrentSpec.mColumns;
-                    Log.v(TAG, "target was " + mGallery.mTargetScroll + " now " + y);
-                    scrollTo(0, y);
-                }
-            }
-        }
-
-        Bitmap scaleTo(int width, int height, Bitmap b) {
-            Matrix m = new Matrix();
-            m.setScale((float)width/64F, (float)height/64F);
-            Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, false);
-            if (b2 != b)
-                b.recycle();
-            return b2;
-        }
-
-        private class ImageBlockManager {
-            private ImageLoader mLoader;
-            private int mBlockCacheFirstBlockNumber = 0;
-
-            // mBlockCache is an array with a starting point which is not necessaryily
-            // zero.  The first element of the array is indicated by mBlockCacheStartOffset.
-            private int mBlockCacheStartOffset = 0;
-            private ImageBlock [] mBlockCache;
-
-            private static final int sRowsPerPage    = 6;   // should compute this
-
-            private static final int sPagesPreCache  = 2;
-            private static final int sPagesPostCache = 2;
-
-            private int mWorkCounter = 0;
-            private boolean mDone = false;
-
-            private Thread mWorkerThread;
-            private Bitmap mMissingImageThumbnailBitmap;
-            private Bitmap mMissingVideoThumbnailBitmap;
-
-            private Drawable mVideoOverlay;
-            private Drawable mVideoMmsErrorOverlay;
-
-            public void dump() {
-                synchronized (ImageBlockManager.this) {
-                    StringBuilder line1 = new StringBuilder();
-                    StringBuilder line2 = new StringBuilder();
-                    if (Config.LOGV)
-                        Log.v(TAG, ">>> mBlockCacheFirstBlockNumber: " + mBlockCacheFirstBlockNumber + " " + mBlockCacheStartOffset);
-                    for (int i = 0; i < mBlockCache.length; i++) {
-                        int index = (mBlockCacheStartOffset + i) % mBlockCache.length;
-                        ImageBlock block = mBlockCache[index];
-                        block.dump(line1, line2);
-                    }
-                    if (Config.LOGV){
-                        Log.v(TAG, line1.toString());
-                        Log.v(TAG, line2.toString());
-                    }
-                }
-            }
-
-            ImageBlockManager() {
-                mLoader = new ImageLoader(mHandler, 1);
-
-                mBlockCache = new ImageBlock[sRowsPerPage * (sPagesPreCache + sPagesPostCache + 1)];
-                for (int i = 0; i < mBlockCache.length; i++) {
-                    mBlockCache[i] = new ImageBlock();
-                }
-
-                mWorkerThread = new Thread(new Runnable() {
-                    public void run() {
-                        while (true) {
-                            int workCounter;
-                            synchronized (ImageBlockManager.this) {
-                                workCounter = mWorkCounter;
-                            }
-                            if (mDone) {
-                                if (Config.LOGV)
-                                    Log.v(TAG, "stopping the loader here " + Thread.currentThread().getName());
-                                if (mLoader != null) {
-                                    mLoader.stop();
-                                }
-                                if (mBlockCache != null) {
-                                    for (int i = 0; i < mBlockCache.length; i++) {
-                                        ImageBlock block = mBlockCache[i];
-                                        if (block != null) {
-                                            block.recycleBitmaps();
-                                            mBlockCache[i] = null;
-                                        }
-                                    }
-                                }
-                                mBlockCache = null;
-                                mBlockCacheStartOffset = 0;
-                                mBlockCacheFirstBlockNumber = 0;
-
-                                break;
-                            }
-
-                            loadNext();
-
-                            synchronized (ImageBlockManager.this) {
-                                if ((workCounter == mWorkCounter) && (! mDone)) {
-                                    try {
-                                        ImageBlockManager.this.wait();
-                                    } catch (InterruptedException ex) {
-                                    }
-                                }
-                            }
-                        }
-                    }
-                });
-                mWorkerThread.setName("image-block-manager");
-                mWorkerThread.start();
-            }
-
-            // Create this bitmap lazily, and only once for all the ImageBlocks to use
-            public Bitmap getErrorBitmap(IImage image) {
-                if (ImageManager.isImage(image)) {
-                    if (mMissingImageThumbnailBitmap == null) {
-                        mMissingImageThumbnailBitmap = BitmapFactory.decodeResource(GridViewSpecial.this.getResources(),
-                                R.drawable.ic_missing_thumbnail_picture);
-                    }
-                    return mMissingImageThumbnailBitmap;
+                int pos = computeSelectedIndex(e);
+                if (pos >= 0 && pos < mGallery.mAllImages.getCount()) {
+                    select(pos, true);
                 } else {
-                    if (mMissingVideoThumbnailBitmap == null) {
-                        mMissingVideoThumbnailBitmap = BitmapFactory.decodeResource(GridViewSpecial.this.getResources(),
-                                R.drawable.ic_missing_thumbnail_video);
-                    }
-                    return mMissingVideoThumbnailBitmap;
+                    select(-1, false);
                 }
+                if (mImageBlockManager != null) {
+                    mImageBlockManager.repaintSelection(mCurrentSelection);
+                }
+                invalidate();
+                return true;
             }
 
-            private ImageBlock getBlockForPos(int pos) {
-                synchronized (ImageBlockManager.this) {
-                    int blockNumber = pos / mCurrentSpec.mColumns;
-                    int delta = blockNumber - mBlockCacheFirstBlockNumber;
-                    if (delta >= 0 && delta < mBlockCache.length) {
-                        int index = (mBlockCacheStartOffset + delta) % mBlockCache.length;
-                        ImageBlock b = mBlockCache[index];
-                        return b;
-                    }
+            @Override
+            public boolean onFling(MotionEvent e1, MotionEvent e2,
+                    float velocityX, float velocityY) {
+                final float maxVelocity = 2500;
+                if (velocityY > maxVelocity) {
+                    velocityY = maxVelocity;
+                } else if (velocityY < -maxVelocity) {
+                    velocityY = -maxVelocity;
                 }
-                return null;
+
+                select(-1, false);
+                if (mFling) {
+                    mScroller = new Scroller(getContext());
+                    mScroller.fling(0, mScrollY, 0, -(int) velocityY, 0, 0, 0,
+                            mMaxScrollY);
+                    computeScroll();
+                }
+                return true;
             }
 
-            private void repaintSelection(int pos) {
-                synchronized (ImageBlockManager.this) {
-                    ImageBlock b = getBlockForPos(pos);
-                    if (b != null) {
-                        b.repaintSelection();
-                    }
-                }
+            @Override
+            public void onLongPress(MotionEvent e) {
+                performLongClick();
             }
 
-            private void onPause() {
-                synchronized (ImageBlockManager.this) {
-                    mDone = true;
-                    ImageBlockManager.this.notify();
-                }
-                if (mWorkerThread != null) {
-                    try {
-                        mWorkerThread.join();
-                        mWorkerThread = null;
-                    } catch (InterruptedException ex) {
-                        //
-                    }
-                }
-                Log.v(TAG, "/ImageBlockManager.onPause");
+            @Override
+            public boolean onScroll(MotionEvent e1, MotionEvent e2,
+                                    float distanceX, float distanceY) {
+                select(-1, false);
+                scrollBy(0, (int) distanceY);
+                invalidate();
+                return true;
             }
 
-            private void getVisibleRange(int [] range) {
-                // try to work around a possible bug in the VM wherein this appears to be null
-                try {
-                    synchronized (ImageBlockManager.this) {
-                        int blockLength = mBlockCache.length;
-                        boolean lookingForStart = true;
-                        ImageBlock prevBlock = null;
-                        for (int i = 0; i < blockLength; i++) {
-                            int index = (mBlockCacheStartOffset + i) % blockLength;
-                            ImageBlock block = mBlockCache[index];
-                            if (lookingForStart) {
-                                if (block.mIsVisible) {
-                                    range[0] = block.mBlockNumber * mCurrentSpec.mColumns;
-                                    lookingForStart = false;
-                                }
-                            } else {
-                                if (!block.mIsVisible || i == blockLength - 1) {
-                                    range[1] = (prevBlock.mBlockNumber * mCurrentSpec.mColumns) + mCurrentSpec.mColumns - 1;
-                                    break;
+            @Override
+            public boolean onSingleTapUp(MotionEvent e) {
+                select(mCurrentSelection, false);
+                int index = computeSelectedIndex(e);
+                if (index >= 0 && index < mGallery.mAllImages.getCount()) {
+                    onSelect(index);
+                    return true;
+                }
+                return false;
+            }
+        });
+        // mGestureDetector.setIsLongpressEnabled(false);
+    }
+
+    public GridViewSpecial(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(context);
+    }
+
+    public GridViewSpecial(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public GridViewSpecial(Context context) {
+        super(context);
+        init(context);
+    }
+
+    @Override
+    protected int computeVerticalScrollRange() {
+        return mMaxScrollY + getHeight();
+    }
+
+    public void setSizeChoice(int choice, int scrollY) {
+        mSizeChoice = choice;
+        clearCache();
+        scrollTo(0, scrollY);
+        requestLayout();
+        invalidate();
+    }
+
+    /**
+     *
+     * @param newSel -2 means use old selection, -1 means remove selection
+     * @param newPressed
+     */
+    public void select(int newSel, boolean newPressed) {
+        if (newSel == -2) {
+            newSel = mCurrentSelection;
+        }
+        int oldSel = mCurrentSelection;
+        if ((oldSel == newSel) && (mCurrentSelectionPressed == newPressed)) {
+            return;
+        }
+
+        mShowSelection = (newSel != -1);
+        mCurrentSelection = newSel;
+        mCurrentSelectionPressed = newPressed;
+        if (mImageBlockManager != null) {
+            mImageBlockManager.repaintSelection(oldSel);
+            mImageBlockManager.repaintSelection(newSel);
+        }
+
+        if (newSel != -1) {
+            ensureVisible(newSel);
+        }
+    }
+
+    private void ensureVisible(int pos) {
+        android.graphics.Rect r = getRectForPosition(pos);
+        int top = getScrollY();
+        int bot = top + getHeight();
+
+        if (r.bottom > bot) {
+            mScroller = new Scroller(getContext());
+            mScroller.startScroll(mScrollX, mScrollY, 0,
+                    r.bottom - getHeight() - mScrollY, 200);
+            computeScroll();
+        } else if (r.top < top) {
+            mScroller = new Scroller(getContext());
+            mScroller.startScroll(mScrollX, mScrollY, 0, r.top - mScrollY, 200);
+            computeScroll();
+        }
+        invalidate();
+    }
+
+    public void start() {
+        if (mGallery.mLayoutComplete) {
+            if (mImageBlockManager == null) {
+                mImageBlockManager = new ImageBlockManager();
+                mImageBlockManager.moveDataWindow(true, true);
+            }
+        }
+    }
+
+    public void onPause() {
+        mScroller = null;
+        if (mImageBlockManager != null) {
+            mImageBlockManager.onPause();
+            mImageBlockManager = null;
+        }
+    }
+
+    public void clearCache() {
+        if (mImageBlockManager != null) {
+            mImageBlockManager.onPause();
+            mImageBlockManager = null;
+        }
+    }
+
+
+    @Override
+    public void onLayout(boolean changed, int left, int top,
+                         int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (mGallery.isFinishing() || mGallery.mPausing) {
+            return;
+        }
+
+        clearCache();
+
+        mCurrentSpec = mCellSizeChoices[mSizeChoice];
+        int oldColumnCount = mCurrentSpec.mColumns;
+
+        int width = right - left;
+        mCurrentSpec.mColumns = 1;
+        width -= mCurrentSpec.mCellWidth;
+        mCurrentSpec.mColumns += width
+                / (mCurrentSpec.mCellWidth + mCurrentSpec.mCellSpacing);
+
+        mCurrentSpec.mLeftEdgePadding = ((right - left)
+                - ((mCurrentSpec.mColumns - 1) * mCurrentSpec.mCellSpacing)
+                - (mCurrentSpec.mColumns * mCurrentSpec.mCellWidth)) / 2;
+        mCurrentSpec.mRightEdgePadding = mCurrentSpec.mLeftEdgePadding;
+
+        int rows = (mGallery.mAllImages.getCount() + mCurrentSpec.mColumns - 1)
+                / mCurrentSpec.mColumns;
+        mMaxScrollY = mCurrentSpec.mCellSpacing
+                + (rows
+                * (mCurrentSpec.mCellSpacing + mCurrentSpec.mCellHeight))
+                - (bottom - top) + mMaxOvershoot;
+        mMinScrollY = 0 - mMaxOvershoot;
+
+        mGallery.mLayoutComplete = true;
+
+        start();
+
+        if (mGallery.mSortAscending && mGallery.mTargetScroll == 0) {
+            scrollTo(0, mMaxScrollY - mMaxOvershoot);
+        } else {
+            if (oldColumnCount != 0) {
+                int y = mGallery.mTargetScroll *
+                        oldColumnCount / mCurrentSpec.mColumns;
+                Log.v(TAG, "target was " + mGallery.mTargetScroll
+                        + " now " + y);
+                scrollTo(0, y);
+            }
+        }
+    }
+
+    Bitmap scaleTo(int width, int height, Bitmap b) {
+        Matrix m = new Matrix();
+        m.setScale((float) width / 64F, (float) height / 64F);
+        Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
+                m, false);
+        if (b2 != b) {
+            b.recycle();
+        }
+        return b2;
+    }
+
+    class ImageBlockManager {
+        private ImageLoader mLoader;
+        private int mBlockCacheFirstBlockNumber = 0;
+
+        // mBlockCache is an array with a starting point which is not
+        // necessarily zero.  The first element of the array is indicated by
+        // mBlockCacheStartOffset.
+        private int mBlockCacheStartOffset = 0;
+        private ImageBlock [] mBlockCache;
+
+        private static final int sRowsPerPage    = 6;   // should compute this
+
+        private static final int sPagesPreCache  = 2;
+        private static final int sPagesPostCache = 2;
+
+        private int mWorkCounter = 0;
+        private boolean mDone = false;
+
+        private Thread mWorkerThread;
+        private Bitmap mMissingImageThumbnailBitmap;
+        private Bitmap mMissingVideoThumbnailBitmap;
+
+        private Drawable mVideoOverlay;
+        private Drawable mVideoMmsErrorOverlay;
+
+        public void dump() {
+            synchronized (ImageBlockManager.this) {
+                StringBuilder line1 = new StringBuilder();
+                StringBuilder line2 = new StringBuilder();
+                if (Config.LOGV) {
+                    Log.v(TAG, ">>> mBlockCacheFirstBlockNumber: "
+                            + mBlockCacheFirstBlockNumber + " "
+                            + mBlockCacheStartOffset);
+                }
+                for (int i = 0; i < mBlockCache.length; i++) {
+                    int index = (mBlockCacheStartOffset + i)
+                            % mBlockCache.length;
+                    ImageBlock block = mBlockCache[index];
+                    block.dump(line1, line2);
+                }
+                if (Config.LOGV){
+                    Log.v(TAG, line1.toString());
+                    Log.v(TAG, line2.toString());
+                }
+            }
+        }
+
+        ImageBlockManager() {
+            mLoader = new ImageLoader(mHandler, 1);
+
+            mBlockCache = new ImageBlock[sRowsPerPage
+                    * (sPagesPreCache + sPagesPostCache + 1)];
+            for (int i = 0; i < mBlockCache.length; i++) {
+                mBlockCache[i] = new ImageBlock();
+            }
+
+            mWorkerThread = new Thread(new Runnable() {
+                public void run() {
+                    while (true) {
+                        int workCounter;
+                        synchronized (ImageBlockManager.this) {
+                            workCounter = mWorkCounter;
+                        }
+                        if (mDone) {
+                            if (Config.LOGV) {
+                                Log.v(TAG, "stopping the loader here "
+                                        + Thread.currentThread().getName());
+                            }
+                            if (mLoader != null) {
+                                mLoader.stop();
+                            }
+                            if (mBlockCache != null) {
+                                for (int i = 0; i < mBlockCache.length; i++) {
+                                    ImageBlock block = mBlockCache[i];
+                                    if (block != null) {
+                                        block.recycleBitmaps();
+                                        mBlockCache[i] = null;
+                                    }
                                 }
                             }
-                            prevBlock = block;
+                            mBlockCache = null;
+                            mBlockCacheStartOffset = 0;
+                            mBlockCacheFirstBlockNumber = 0;
+
+                            break;
+                        }
+
+                        loadNext();
+
+                        synchronized (ImageBlockManager.this) {
+                            if ((workCounter == mWorkCounter) && (!mDone)) {
+                                try {
+                                    ImageBlockManager.this.wait();
+                                } catch (InterruptedException ex) {
+                                }
+                            }
                         }
                     }
-                } catch (NullPointerException ex) {
-                    Log.e(TAG, "this is somewhat null, what up?");
-                    range[0] = range[1] = 0;
+                }
+            });
+            mWorkerThread.setName("image-block-manager");
+            mWorkerThread.start();
+        }
+
+        // Create this bitmap lazily, and only once for all the ImageBlocks to
+        // use
+        public Bitmap getErrorBitmap(IImage image) {
+            if (ImageManager.isImage(image)) {
+                if (mMissingImageThumbnailBitmap == null) {
+                    mMissingImageThumbnailBitmap =
+                            BitmapFactory.decodeResource(
+                            GridViewSpecial.this.getResources(),
+                            R.drawable.ic_missing_thumbnail_picture);
+                }
+                return mMissingImageThumbnailBitmap;
+            } else {
+                if (mMissingVideoThumbnailBitmap == null) {
+                    mMissingVideoThumbnailBitmap =
+                            BitmapFactory.decodeResource(
+                            GridViewSpecial.this.getResources(),
+                            R.drawable.ic_missing_thumbnail_video);
+                }
+                return mMissingVideoThumbnailBitmap;
+            }
+        }
+
+        private ImageBlock getBlockForPos(int pos) {
+            synchronized (ImageBlockManager.this) {
+                int blockNumber = pos / mCurrentSpec.mColumns;
+                int delta = blockNumber - mBlockCacheFirstBlockNumber;
+                if (delta >= 0 && delta < mBlockCache.length) {
+                    int index = (mBlockCacheStartOffset + delta)
+                            % mBlockCache.length;
+                    ImageBlock b = mBlockCache[index];
+                    return b;
                 }
             }
+            return null;
+        }
 
-            private void loadNext() {
-                final int blockHeight = (mCurrentSpec.mCellSpacing + mCurrentSpec.mCellHeight);
+        private void repaintSelection(int pos) {
+            synchronized (ImageBlockManager.this) {
+                ImageBlock b = getBlockForPos(pos);
+                if (b != null) {
+                    b.repaintSelection();
+                }
+            }
+        }
 
-                final int firstVisBlock = Math.max(0, (mScrollY - mCurrentSpec.mCellSpacing) / blockHeight);
-                final int lastVisBlock  = (mScrollY - mCurrentSpec.mCellSpacing + getHeight()) / blockHeight;
+        private void onPause() {
+            synchronized (ImageBlockManager.this) {
+                mDone = true;
+                ImageBlockManager.this.notify();
+            }
+            if (mWorkerThread != null) {
+                try {
+                    mWorkerThread.join();
+                    mWorkerThread = null;
+                } catch (InterruptedException ex) {
+                    //
+                }
+            }
+            Log.v(TAG, "/ImageBlockManager.onPause");
+        }
 
-//              Log.v(TAG, "firstVisBlock == " + firstVisBlock + "; lastVisBlock == " + lastVisBlock);
-
+        void getVisibleRange(int [] range) {
+            // try to work around a possible bug in the VM wherein this appears
+            // to be null
+            try {
                 synchronized (ImageBlockManager.this) {
-                    ImageBlock [] blocks = mBlockCache;
-                    int numBlocks = blocks.length;
-                    if (mDirectionBiasDown) {
-                        int first = (mBlockCacheStartOffset + (firstVisBlock - mBlockCacheFirstBlockNumber)) % blocks.length;
-                        for (int i = 0; i < numBlocks; i++) {
-                            int j = first + i;
-                            if (j >= numBlocks)
-                                j -= numBlocks;
-                            ImageBlock b = blocks[j];
-                            if (b.startLoading() > 0)
-                                break;
-                        }
-                    } else {
-                        int first = (mBlockCacheStartOffset + (lastVisBlock - mBlockCacheFirstBlockNumber)) % blocks.length;
-                        for (int i = 0; i < numBlocks; i++) {
-                            int j = first - i;
-                            if (j < 0)
-                                j += numBlocks;
-                            ImageBlock b = blocks[j];
-                            if (b.startLoading() > 0)
-                                break;
-                        }
-                    }
-                    if (sDump)
-                        this.dump();
-                }
-            }
-
-            private void moveDataWindow(boolean directionBiasDown, boolean forceRefresh) {
-                final int blockHeight = (mCurrentSpec.mCellSpacing + mCurrentSpec.mCellHeight);
-
-                final int firstVisBlock = (mScrollY - mCurrentSpec.mCellSpacing) / blockHeight;
-                final int lastVisBlock  = (mScrollY - mCurrentSpec.mCellSpacing + getHeight()) / blockHeight;
-
-                final int preCache = sPagesPreCache;
-                final int startBlock = Math.max(0, firstVisBlock - (preCache * sRowsPerPage));
-
-//              Log.v(TAG, "moveDataWindow directionBiasDown == " + directionBiasDown + "; preCache is " + preCache);
-                synchronized (ImageBlockManager.this) {
-                    boolean any = false;
-                    ImageBlock [] blocks = mBlockCache;
-                    int numBlocks = blocks.length;
-
-                    int delta = startBlock - mBlockCacheFirstBlockNumber;
-
-                    mBlockCacheFirstBlockNumber = startBlock;
-                    if (Math.abs(delta) > numBlocks || forceRefresh) {
-                        for (int i = 0; i < numBlocks; i++) {
-                            int blockNum = startBlock + i;
-                            blocks[i].setStart(blockNum);
-                            any = true;
-                        }
-                        mBlockCacheStartOffset = 0;
-                    } else if (delta > 0) {
-                        mBlockCacheStartOffset += delta;
-                        if (mBlockCacheStartOffset >= numBlocks)
-                            mBlockCacheStartOffset -= numBlocks;
-
-                        for (int i = delta; i > 0; i--) {
-                            int index = (mBlockCacheStartOffset + numBlocks - i) % numBlocks;
-                            int blockNum = mBlockCacheFirstBlockNumber + numBlocks - i;
-                            blocks[index].setStart(blockNum);
-                            any = true;
-                        }
-                    } else if (delta < 0) {
-                        mBlockCacheStartOffset += delta;
-                        if (mBlockCacheStartOffset < 0)
-                            mBlockCacheStartOffset += numBlocks;
-
-                        for (int i = 0; i < -delta; i++) {
-                            int index = (mBlockCacheStartOffset + i) % numBlocks;
-                            int blockNum = mBlockCacheFirstBlockNumber + i;
-                            blocks[index].setStart(blockNum);
-                            any = true;
-                        }
-                    }
-
-                    for (int i = 0; i < numBlocks; i++) {
-                        int index = (mBlockCacheStartOffset + i) % numBlocks;
-                        ImageBlock block = blocks[index];
-                        int blockNum = block.mBlockNumber; // mBlockCacheFirstBlockNumber + i;
-                        boolean isVis = blockNum >= firstVisBlock && blockNum <= lastVisBlock;
-//                      Log.v(TAG, "blockNum " + blockNum + " setting vis to " + isVis);
-                        block.setVisibility(isVis);
-                    }
-
-                    if (sDump)
-                        mImageBlockManager.dump();
-
-                    if (any) {
-                        ImageBlockManager.this.notify();
-                        mWorkCounter += 1;
-                    }
-                }
-                if (sDump)
-                    dump();
-            }
-
-            private void check() {
-                ImageBlock [] blocks = mBlockCache;
-                int blockLength = blocks.length;
-
-                // check the results
-                for (int i = 0; i < blockLength; i++) {
-                    int index = (mBlockCacheStartOffset + i) % blockLength;
-                    if (blocks[index].mBlockNumber != mBlockCacheFirstBlockNumber + i) {
-                        if (blocks[index].mBlockNumber != -1)
-                            Log.e(TAG, "at " + i + " block cache corrupted; found " + blocks[index].mBlockNumber + " but wanted " + (mBlockCacheFirstBlockNumber + i) + "; offset is " + mBlockCacheStartOffset);
-                    }
-                }
-                if (true) {
-                    StringBuilder sb  = new StringBuilder();
+                    int blockLength = mBlockCache.length;
+                    boolean lookingForStart = true;
+                    ImageBlock prevBlock = null;
                     for (int i = 0; i < blockLength; i++) {
                         int index = (mBlockCacheStartOffset + i) % blockLength;
-                        ImageBlock b = blocks[index];
-                        if (b.mRequestedMask != 0)
-                            sb.append("X");
-                        else
-                            sb.append(String.valueOf(b.mBlockNumber) + " ");
+                        ImageBlock block = mBlockCache[index];
+                        if (lookingForStart) {
+                            if (block.mIsVisible) {
+                                range[0] = block.mBlockNumber
+                                        * mCurrentSpec.mColumns;
+                                lookingForStart = false;
+                            }
+                        } else {
+                            if (!block.mIsVisible || i == blockLength - 1) {
+                                range[1] = (prevBlock.mBlockNumber
+                                        * mCurrentSpec.mColumns)
+                                        + mCurrentSpec.mColumns - 1;
+                                break;
+                            }
+                        }
+                        prevBlock = block;
                     }
-                    if (Config.LOGV)
-                        Log.v(TAG, "moveDataWindow " + sb.toString());
+                }
+            } catch (NullPointerException ex) {
+                Log.e(TAG, "this is somewhat null, what up?");
+                range[0] = range[1] = 0;
+            }
+        }
+
+        private void loadNext() {
+            final int blockHeight = (mCurrentSpec.mCellSpacing
+                    + mCurrentSpec.mCellHeight);
+
+            final int firstVisBlock =
+                    Math.max(0, (mScrollY - mCurrentSpec.mCellSpacing)
+                    / blockHeight);
+            final int lastVisBlock = 
+                    (mScrollY - mCurrentSpec.mCellSpacing + getHeight())
+                    / blockHeight;
+
+            synchronized (ImageBlockManager.this) {
+                ImageBlock [] blocks = mBlockCache;
+                int numBlocks = blocks.length;
+                if (mDirectionBiasDown) {
+                    int first = (mBlockCacheStartOffset
+                            + (firstVisBlock - mBlockCacheFirstBlockNumber))
+                            % blocks.length;
+                    for (int i = 0; i < numBlocks; i++) {
+                        int j = first + i;
+                        if (j >= numBlocks) {
+                            j -= numBlocks;
+                        }
+                        ImageBlock b = blocks[j];
+                        if (b.startLoading() > 0) {
+                            break;
+                        }
+                    }
+                } else {
+                    int first = (mBlockCacheStartOffset
+                            + (lastVisBlock - mBlockCacheFirstBlockNumber))
+                            % blocks.length;
+                    for (int i = 0; i < numBlocks; i++) {
+                        int j = first - i;
+                        if (j < 0) {
+                            j += numBlocks;
+                        }
+                        ImageBlock b = blocks[j];
+                        if (b.startLoading() > 0) {
+                            break;
+                        }
+                    }
+                }
+                if (DUMP) {
+                    this.dump();
+                }
+            }
+        }
+
+        private void moveDataWindow(boolean directionBiasDown,
+                boolean forceRefresh) {
+            final int blockHeight = (mCurrentSpec.mCellSpacing
+                    + mCurrentSpec.mCellHeight);
+
+            final int firstVisBlock = (mScrollY - mCurrentSpec.mCellSpacing)
+                    / blockHeight;
+            final int lastVisBlock =
+                    (mScrollY - mCurrentSpec.mCellSpacing + getHeight())
+                    / blockHeight;
+
+            final int preCache = sPagesPreCache;
+            final int startBlock = Math.max(0,
+                    firstVisBlock - (preCache * sRowsPerPage));
+
+            synchronized (ImageBlockManager.this) {
+                boolean any = false;
+                ImageBlock [] blocks = mBlockCache;
+                int numBlocks = blocks.length;
+
+                int delta = startBlock - mBlockCacheFirstBlockNumber;
+
+                mBlockCacheFirstBlockNumber = startBlock;
+                if (Math.abs(delta) > numBlocks || forceRefresh) {
+                    for (int i = 0; i < numBlocks; i++) {
+                        int blockNum = startBlock + i;
+                        blocks[i].setStart(blockNum);
+                        any = true;
+                    }
+                    mBlockCacheStartOffset = 0;
+                } else if (delta > 0) {
+                    mBlockCacheStartOffset += delta;
+                    if (mBlockCacheStartOffset >= numBlocks) {
+                        mBlockCacheStartOffset -= numBlocks;
+                    }
+
+                    for (int i = delta; i > 0; i--) {
+                        int index = (mBlockCacheStartOffset + numBlocks - i)
+                                % numBlocks;
+                        int blockNum = mBlockCacheFirstBlockNumber
+                                + numBlocks - i;
+                        blocks[index].setStart(blockNum);
+                        any = true;
+                    }
+                } else if (delta < 0) {
+                    mBlockCacheStartOffset += delta;
+                    if (mBlockCacheStartOffset < 0) {
+                        mBlockCacheStartOffset += numBlocks;
+                    }
+
+                    for (int i = 0; i < -delta; i++) {
+                        int index = (mBlockCacheStartOffset + i) % numBlocks;
+                        int blockNum = mBlockCacheFirstBlockNumber + i;
+                        blocks[index].setStart(blockNum);
+                        any = true;
+                    }
+                }
+
+                for (int i = 0; i < numBlocks; i++) {
+                    int index = (mBlockCacheStartOffset + i) % numBlocks;
+                    ImageBlock block = blocks[index];
+                    int blockNum = block.mBlockNumber; 
+                    boolean isVis = blockNum >= firstVisBlock
+                            && blockNum <= lastVisBlock;
+                    block.setVisibility(isVis);
+                }
+
+                if (DUMP) {
+                    mImageBlockManager.dump();
+                }
+
+                if (any) {
+                    ImageBlockManager.this.notify();
+                    mWorkCounter += 1;
+                }
+            }
+            if (DUMP) {
+                dump();
+            }
+        }
+
+        private void check() {
+            ImageBlock [] blocks = mBlockCache;
+            int blockLength = blocks.length;
+
+            // check the results
+            for (int i = 0; i < blockLength; i++) {
+                int index = (mBlockCacheStartOffset + i) % blockLength;
+                if (blocks[index].mBlockNumber
+                        != mBlockCacheFirstBlockNumber + i) {
+                    if (blocks[index].mBlockNumber != -1) {
+                        Log.e(TAG, "at " + i
+                                + " block cache corrupted; found "
+                                + blocks[index].mBlockNumber
+                                + " but wanted "
+                                + (mBlockCacheFirstBlockNumber + i)
+                                + "; offset is " + mBlockCacheStartOffset);
+                    }
+                }
+            }
+            if (true) {
+                StringBuilder sb  = new StringBuilder();
+                for (int i = 0; i < blockLength; i++) {
+                    int index = (mBlockCacheStartOffset + i) % blockLength;
+                    ImageBlock b = blocks[index];
+                    if (b.mRequestedMask != 0) {
+                        sb.append("X");
+                    } else {
+                        sb.append(String.valueOf(b.mBlockNumber) + " ");
+                    }
+                }
+                if (Config.LOGV) {
+                    Log.v(TAG, "moveDataWindow " + sb.toString());
+                }
+            }
+        }
+
+        void doDraw(Canvas canvas) {
+            synchronized (ImageBlockManager.this) {
+                ImageBlockManager.ImageBlock [] blocks = mBlockCache;
+                int blockCount = 0;
+
+                if (blocks[0] == null) {
+                    return;
+                }
+
+                final int thisHeight = getHeight();
+                final int thisWidth  = getWidth();
+                final int height = blocks[0].mBitmap.getHeight();
+                final int scrollPos = mScrollY;
+
+                int currentBlock = (scrollPos < 0)
+                        ? ((scrollPos - height + 1) / height)
+                        : (scrollPos / height);
+
+                while (true) {
+                    final int yPos = currentBlock * height;
+                    if (yPos >= scrollPos + thisHeight) {
+                        break;
+                    }
+
+                    if (currentBlock < 0) {
+                        canvas.drawRect(0, yPos, thisWidth, 0, mGridViewPaint);
+                        currentBlock += 1;
+                        continue;
+                    }
+                    int effectiveOffset = 
+                            (mBlockCacheStartOffset 
+                            + (currentBlock++ - mBlockCacheFirstBlockNumber)) 
+                            % blocks.length;
+                    if (effectiveOffset < 0 
+                            || effectiveOffset >= blocks.length) {
+                        break;
+                    }
+
+                    ImageBlock block = blocks[effectiveOffset];
+                    if (block == null) {
+                        break;
+                    }
+                    synchronized (block) {
+                        Bitmap b = block.mBitmap;
+                        if (b == null) {
+                            break;
+                        }
+                        canvas.drawBitmap(b, 0, yPos, mGridViewPaint);
+                        blockCount += 1;
+                    }
+                }
+            }
+        }
+
+        int blockHeight() {
+            return mCurrentSpec.mCellSpacing + mCurrentSpec.mCellHeight;
+        }
+
+        private class ImageBlock {
+            Drawable mCellOutline;
+            Bitmap mBitmap = Bitmap.createBitmap(getWidth(), blockHeight(),
+                    Bitmap.Config.RGB_565);;
+            Canvas mCanvas = new Canvas(mBitmap);
+            Paint mPaint = new Paint();
+
+            int     mBlockNumber;
+
+            // columns which have been requested to the loader
+            int     mRequestedMask; 
+            
+            // columns which have been completed from the loader
+            int     mCompletedMask;
+            boolean mIsVisible;
+
+            public void dump(StringBuilder line1, StringBuilder line2) {
+                synchronized (ImageBlock.this) {
+                    line2.append(mCompletedMask != 0xF ? 'L' : '_');
+                    line1.append(mIsVisible ? 'V' : ' ');
                 }
             }
 
-            void doDraw(Canvas canvas) {
-                synchronized (ImageBlockManager.this) {
-                    ImageBlockManager.ImageBlock [] blocks = mBlockCache;
-                    int blockCount = 0;
+            ImageBlock() {
+                mPaint.setTextSize(14F);
+                mPaint.setStyle(Paint.Style.FILL);
 
-                    if (blocks[0] == null) {
+                mBlockNumber = -1;
+                mCellOutline = GridViewSpecial.this.getResources()
+                        .getDrawable(android.R.drawable.gallery_thumb);
+            }
+
+            private void recycleBitmaps() {
+                synchronized (ImageBlock.this) {
+                    mBitmap.recycle();
+                    mBitmap = null;
+                }
+            }
+
+            private void cancelExistingRequests() {
+                synchronized (ImageBlock.this) {
+                    for (int i = 0; i < mCurrentSpec.mColumns; i++) {
+                        int mask = (1 << i);
+                        if ((mRequestedMask & mask) != 0) {
+                            int pos =
+                                    (mBlockNumber * mCurrentSpec.mColumns) + i;
+                            if (mLoader.cancel(
+                                    mGallery.mAllImages.getImageAt(pos))) {
+                                mRequestedMask &= ~mask;
+                            }
+                        }
+                    }
+                }
+            }
+
+            private void setStart(final int blockNumber) {
+                synchronized (ImageBlock.this) {
+                    if (blockNumber == mBlockNumber) {
                         return;
                     }
 
-                    final int thisHeight = getHeight();
-                    final int thisWidth  = getWidth();
-                    final int height = blocks[0].mBitmap.getHeight();
-                    final int scrollPos = mScrollY;
+                    cancelExistingRequests();
 
-                    int currentBlock = (scrollPos < 0) ? ((scrollPos-height+1) / height) : (scrollPos / height);
+                    mBlockNumber = blockNumber;
+                    mRequestedMask = 0;
+                    mCompletedMask = 0;
+                    mCanvas.drawColor(0xFF000000);
+                    mPaint.setColor(0xFFDDDDDD);
+                    int imageNumber = blockNumber * mCurrentSpec.mColumns;
+                    int lastImageNumber = mGallery.mAllImages.getCount() - 1;
 
-                    while (true) {
-                        final int yPos = currentBlock * height;
-                        if (yPos >= scrollPos + thisHeight)
+                    int spacing = mCurrentSpec.mCellSpacing;
+                    int leftSpacing = mCurrentSpec.mLeftEdgePadding;
+
+                    final int yPos = spacing;
+
+                    for (int col = 0; col < mCurrentSpec.mColumns; col++) {
+                        if (imageNumber++ >= lastImageNumber) {
                             break;
+                        }
+                        final int xPos = leftSpacing
+                                + (col * (mCurrentSpec.mCellWidth + spacing));
+                        mCanvas.drawRect(xPos, yPos,
+                                xPos + mCurrentSpec.mCellWidth,
+                                yPos + mCurrentSpec.mCellHeight, mPaint);
+                        paintSel(0, xPos, yPos);
+                    }
+                }
+            }
 
-                        if (currentBlock < 0) {
-                            canvas.drawRect(0, yPos, thisWidth, 0, mGridViewPaint);
-                            currentBlock += 1;
+            private boolean setVisibility(boolean isVis) {
+                synchronized (ImageBlock.this) {
+                    boolean retval = mIsVisible != isVis;
+                    mIsVisible = isVis;
+                    return retval;
+                }
+            }
+
+            private int startLoading() {
+                synchronized (ImageBlock.this) {
+                    final int startRow = mBlockNumber;
+                    int count = mGallery.mAllImages.getCount();
+
+                    if (startRow == -1) {
+                        return 0;
+                    }
+
+                    if ((startRow * mCurrentSpec.mColumns) >= count) {
+                        return 0;
+                    }
+
+                    int retVal = 0;
+                    int base = (mBlockNumber * mCurrentSpec.mColumns);
+                    for (int col = 0; col < mCurrentSpec.mColumns; col++) {
+                        if ((mCompletedMask & (1 << col)) != 0) {
                             continue;
                         }
-                        int effectiveOffset = (mBlockCacheStartOffset + (currentBlock++ - mBlockCacheFirstBlockNumber)) % blocks.length;
-                        if (effectiveOffset < 0 || effectiveOffset >= blocks.length) {
-                            break;
-                        }
-
-                        ImageBlock block = blocks[effectiveOffset];
-                        if (block == null) {
-                            break;
-                        }
-                        synchronized (block) {
-                            Bitmap b = block.mBitmap;
-                            if (b == null) {
-                                break;
-                            }
-                            canvas.drawBitmap(b, 0, yPos, mGridViewPaint);
-                            blockCount += 1;
-                        }
-                    }
-                }
-            }
-
-            int blockHeight() {
-                return mCurrentSpec.mCellSpacing + mCurrentSpec.mCellHeight;
-            }
-
-            private class ImageBlock {
-                Drawable mCellOutline;
-                Bitmap mBitmap = Bitmap.createBitmap(getWidth(), blockHeight(),
-                        Bitmap.Config.RGB_565);;
-                Canvas mCanvas = new Canvas(mBitmap);
-                Paint mPaint = new Paint();
-
-                int     mBlockNumber;
-                int     mRequestedMask;   // columns which have been requested to the loader
-                int     mCompletedMask;   // columns which have been completed from the loader
-                boolean mIsVisible;
-
-                public void dump(StringBuilder line1, StringBuilder line2) {
-                    synchronized (ImageBlock.this) {
-//                        Log.v(TAG, "block " + mBlockNumber + " isVis == " + mIsVisible);
-                        line2.append(mCompletedMask != 0xF ? 'L' : '_');
-                        line1.append(mIsVisible ? 'V' : ' ');
-                    }
-                }
-
-                ImageBlock() {
-                    mPaint.setTextSize(14F);
-                    mPaint.setStyle(Paint.Style.FILL);
-
-                    mBlockNumber = -1;
-                    mCellOutline = GridViewSpecial.this.getResources().getDrawable(android.R.drawable.gallery_thumb);
-                }
-
-                private void recycleBitmaps() {
-                    synchronized (ImageBlock.this) {
-                        mBitmap.recycle();
-                        mBitmap = null;
-                    }
-                }
-
-                private void cancelExistingRequests() {
-                    synchronized (ImageBlock.this) {
-                        for (int i = 0; i < mCurrentSpec.mColumns; i++) {
-                            int mask = (1 << i);
-                            if ((mRequestedMask & mask) != 0) {
-                                int pos = (mBlockNumber * mCurrentSpec.mColumns) + i;
-                                if (mLoader.cancel(mGallery.mAllImages.getImageAt(pos))) {
-                                    mRequestedMask &= ~mask;
-                                }
-                            }
-                        }
-                    }
-                }
-
-                private void setStart(final int blockNumber) {
-                    synchronized (ImageBlock.this) {
-                        if (blockNumber == mBlockNumber)
-                            return;
-
-                        cancelExistingRequests();
-
-                        mBlockNumber = blockNumber;
-                        mRequestedMask = 0;
-                        mCompletedMask = 0;
-                        mCanvas.drawColor(0xFF000000);
-                        mPaint.setColor(0xFFDDDDDD);
-                        int imageNumber = blockNumber * mCurrentSpec.mColumns;
-                        int lastImageNumber = mGallery.mAllImages.getCount() - 1;
 
                         int spacing = mCurrentSpec.mCellSpacing;
                         int leftSpacing = mCurrentSpec.mLeftEdgePadding;
-
                         final int yPos = spacing;
+                        final int xPos = leftSpacing
+                                + (col * (mCurrentSpec.mCellWidth + spacing));
 
-                        for (int col = 0; col < mCurrentSpec.mColumns; col++) {
-                            if (imageNumber++ >= lastImageNumber)
-                                break;
-                            final int xPos = leftSpacing + (col * (mCurrentSpec.mCellWidth + spacing));
-                            mCanvas.drawRect(xPos, yPos, xPos+mCurrentSpec.mCellWidth, yPos+mCurrentSpec.mCellHeight, mPaint);
-                            paintSel(0, xPos, yPos);
-                        }
-                    }
-                }
-
-                private boolean setVisibility(boolean isVis) {
-                    synchronized (ImageBlock.this) {
-                        boolean retval = mIsVisible != isVis;
-                        mIsVisible = isVis;
-                        return retval;
-                    }
-                }
-
-                private int startLoading() {
-                    synchronized (ImageBlock.this) {
-                        final int startRow = mBlockNumber;
-                        int count = mGallery.mAllImages.getCount();
-
-                        if (startRow == -1)
-                            return 0;
-
-                        if ((startRow * mCurrentSpec.mColumns) >= count) {
-                            return 0;
+                        int pos = base + col;
+                        if (pos >= count) {
+                            break;
                         }
 
-                        int retVal = 0;
-                        int base = (mBlockNumber * mCurrentSpec.mColumns);
-                        for (int col = 0; col < mCurrentSpec.mColumns; col++) {
-                            if ((mCompletedMask & (1 << col)) != 0) {
-                                continue;
-                            }
+                        IImage image = mGallery.mAllImages.getImageAt(pos);
+                        if (image != null) {
+                            loadImage(base, col, image, xPos, yPos);
+                            retVal += 1;
+                        }
+                    }
+                    return retVal;
 
-                            int spacing = mCurrentSpec.mCellSpacing;
-                            int leftSpacing = mCurrentSpec.mLeftEdgePadding;
-                            final int yPos = spacing;
-                            final int xPos = leftSpacing + (col * (mCurrentSpec.mCellWidth + spacing));
+                }
+            }
 
-                            int pos = base + col;
-                            if (pos >= count)
-                                break;
+            Bitmap resizeBitmap(Bitmap b) {
+                // assume they're both square for now
+                if (b == null || (b.getWidth() == mCurrentSpec.mCellWidth
+                        && b.getHeight() == mCurrentSpec.mCellHeight)) {
+                    return b;
+                }
+                float scale = (float) mCurrentSpec.mCellWidth
+                        / (float) b.getWidth();
+                Matrix m = new Matrix();
+                m.setScale(scale, scale, b.getWidth(), b.getHeight());
+                Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(),
+                        b.getHeight(), m, false);
+                return b2;
+            }
 
-                            IImage image = mGallery.mAllImages.getImageAt(pos);
-                            if (image != null) {
-//                              Log.v(TAG, "calling loadImage " + (base + col));
-                                loadImage(base, col, image, xPos, yPos);
-                                retVal += 1;
+            private void drawBitmap(IImage image, int base, int baseOffset,
+                    Bitmap b, int xPos, int yPos) {
+                mCanvas.setBitmap(mBitmap);
+                if (b != null) {
+                    // if the image is close to the target size then crop,
+                    // otherwise scale both the bitmap and the view should be
+                    // square but I suppose that could change in the future.
+                    int w = mCurrentSpec.mCellWidth;
+                    int h = mCurrentSpec.mCellHeight;
+
+                    int bw = b.getWidth();
+                    int bh = b.getHeight();
+
+                    int deltaW = bw - w;
+                    int deltaH = bh - h;
+
+                    if (deltaW < 10 && deltaH < 10) {
+                        int halfDeltaW = deltaW / 2;
+                        int halfDeltaH = deltaH / 2;
+                        android.graphics.Rect src =
+                                new android.graphics.Rect(0 + halfDeltaW,
+                                0 + halfDeltaH, bw - halfDeltaW,
+                                bh - halfDeltaH);
+                        android.graphics.Rect dst =
+                                new android.graphics.Rect(xPos, yPos,
+                                xPos + w, yPos + h);
+                        if (src.width() != dst.width()
+                                || src.height() != dst.height()) {
+                            if (Config.LOGV){
+                                Log.v(TAG, "nope... width doesn't match "
+                                        + src.width() + " " + dst.width());
+                                Log.v(TAG, "nope... height doesn't match "
+                                        + src.height() + " " + dst.height());
                             }
                         }
-                        return retVal;
-
-                    }
-                }
-
-                Bitmap resizeBitmap(Bitmap b) {
-                    // assume they're both square for now
-                    if (b == null || (b.getWidth() == mCurrentSpec.mCellWidth && b.getHeight() == mCurrentSpec.mCellHeight)) {
-                        return b;
-                    }
-                    float scale = (float) mCurrentSpec.mCellWidth / (float)b.getWidth();
-                    Matrix m = new Matrix();
-                    m.setScale(scale, scale, b.getWidth(), b.getHeight());
-                    Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, false);
-                    return b2;
-                }
-
-                private void drawBitmap(IImage image, int base, int baseOffset, Bitmap b, int xPos, int yPos) {
-                    mCanvas.setBitmap(mBitmap);
-                    if (b != null) {
-                        // if the image is close to the target size then crop, otherwise scale
-                        // both the bitmap and the view should be square but I suppose that could
-                        // change in the future.
-                        int w = mCurrentSpec.mCellWidth;
-                        int h = mCurrentSpec.mCellHeight;
-
-                        int bw = b.getWidth();
-                        int bh = b.getHeight();
-
-                        int deltaW = bw - w;
-                        int deltaH = bh - h;
-
-                        if (deltaW < 10 && deltaH < 10) {
-                            int halfDeltaW = deltaW / 2;
-                            int halfDeltaH = deltaH / 2;
-                            android.graphics.Rect src = new android.graphics.Rect(0+halfDeltaW, 0+halfDeltaH, bw-halfDeltaW, bh-halfDeltaH);
-                            android.graphics.Rect dst = new android.graphics.Rect(xPos, yPos, xPos+w, yPos+h);
-                            if (src.width() != dst.width() || src.height() != dst.height()) {
-                                if (Config.LOGV){
-                                    Log.v(TAG, "nope... width doesn't match " + src.width() + " " + dst.width());
-                                    Log.v(TAG, "nope... height doesn't match " + src.height() + " " + dst.height());
-                                }
-                            }
-                            mCanvas.drawBitmap(b, src, dst, mPaint);
-                        } else {
-                            android.graphics.Rect src = new android.graphics.Rect(0, 0, bw, bh);
-                            android.graphics.Rect dst = new android.graphics.Rect(xPos, yPos, xPos+w, yPos+h);
-                            mCanvas.drawBitmap(b, src, dst, mPaint);
-                        }
+                        mCanvas.drawBitmap(b, src, dst, mPaint);
                     } else {
-                        // If the thumbnail cannot be drawn, put up an error icon instead
-                        Bitmap error = mImageBlockManager.getErrorBitmap(image);
-                        int width = error.getWidth();
-                        int height = error.getHeight();
-                        Rect source = new Rect(0, 0, width, height);
-                        int left = (mCurrentSpec.mCellWidth - width) / 2 + xPos;
-                        int top = (mCurrentSpec.mCellHeight - height) / 2 + yPos;
-                        Rect dest = new Rect(left, top, left + width, top + height);
-                        mCanvas.drawBitmap(error, source, dest, mPaint);
+                        android.graphics.Rect src =
+                                new android.graphics.Rect(0, 0, bw, bh);
+                        android.graphics.Rect dst =
+                                new android.graphics.Rect(xPos, yPos, xPos + w,
+                                yPos + h);
+                        mCanvas.drawBitmap(b, src, dst, mPaint);
                     }
-                    if (ImageManager.isVideo(image)) {
-                        Drawable overlay = null;
-                        long size = MenuHelper.getImageFileSize(image);
-                        if (size >= 0 && size <= mVideoSizeLimit) {
-                            if (mVideoOverlay == null) {
-                                mVideoOverlay = getResources().getDrawable(
-                                        R.drawable.ic_gallery_video_overlay);
-                            }
-                            overlay = mVideoOverlay;
-                        } else {
-                            if (mVideoMmsErrorOverlay == null) {
-                                mVideoMmsErrorOverlay = getResources().getDrawable(
-                                        R.drawable.ic_error_mms_video_overlay);
-                            }
-                            overlay = mVideoMmsErrorOverlay;
-                            Paint paint = new Paint();
-                            paint.setARGB(0x80, 0x00, 0x00, 0x00);
-                            mCanvas.drawRect(xPos, yPos, xPos + mCurrentSpec.mCellWidth,
-                                    yPos + mCurrentSpec.mCellHeight, paint);
-                        }
-                        int width = overlay.getIntrinsicWidth();
-                        int height = overlay.getIntrinsicHeight();
-                        int left = (mCurrentSpec.mCellWidth - width) / 2 + xPos;
-                        int top = (mCurrentSpec.mCellHeight - height) / 2 + yPos;
-                        Rect newBounds = new Rect(left, top, left + width, top + height);
-                        overlay.setBounds(newBounds);
-                        overlay.draw(mCanvas);
-                    }
-                    paintSel(base + baseOffset, xPos, yPos);
+                } else {
+                    // If the thumbnail cannot be drawn, put up an error icon
+                    // instead
+                    Bitmap error = mImageBlockManager.getErrorBitmap(image);
+                    int width = error.getWidth();
+                    int height = error.getHeight();
+                    Rect source = new Rect(0, 0, width, height);
+                    int left = (mCurrentSpec.mCellWidth - width) / 2 + xPos;
+                    int top = (mCurrentSpec.mCellHeight - height) / 2 + yPos;
+                    Rect dest = new Rect(left, top, left + width, top + height);
+                    mCanvas.drawBitmap(error, source, dest, mPaint);
                 }
-
-                private void repaintSelection() {
-                    int count = mGallery.mAllImages.getCount();
-                    int startPos = mBlockNumber * mCurrentSpec.mColumns;
-                    synchronized (ImageBlock.this) {
-                        for (int i = 0; i < mCurrentSpec.mColumns; i++) {
-                            int pos = startPos + i;
-
-                            if (pos >= count)
-                                break;
-
-                            int row = 0; // i / mCurrentSpec.mColumns;
-                            int col = i - (row * mCurrentSpec.mColumns);
-
-                            // this is duplicated from getOrKick (TODO: don't duplicate this code)
-                            int spacing = mCurrentSpec.mCellSpacing;
-                            int leftSpacing = mCurrentSpec.mLeftEdgePadding;
-                            final int yPos = spacing + (row * (mCurrentSpec.mCellHeight + spacing));
-                            final int xPos = leftSpacing + (col * (mCurrentSpec.mCellWidth + spacing));
-
-                            paintSel(pos, xPos, yPos);
+                if (ImageManager.isVideo(image)) {
+                    Drawable overlay = null;
+                    long size = MenuHelper.getImageFileSize(image);
+                    if (size >= 0 && size <= mVideoSizeLimit) {
+                        if (mVideoOverlay == null) {
+                            mVideoOverlay = getResources().getDrawable(
+                                    R.drawable.ic_gallery_video_overlay);
                         }
-                    }
-                }
-
-                private void paintSel(int pos, int xPos, int yPos) {
-                    int[] stateSet = EMPTY_STATE_SET;
-                    if (pos == mCurrentSelection && mShowSelection) {
-                        if (mCurrentSelectionPressed) {
-                            stateSet = PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
-                        } else {
-                            stateSet = ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
+                        overlay = mVideoOverlay;
+                    } else {
+                        if (mVideoMmsErrorOverlay == null) {
+                            mVideoMmsErrorOverlay = getResources().getDrawable(
+                                    R.drawable.ic_error_mms_video_overlay);
                         }
+                        overlay = mVideoMmsErrorOverlay;
+                        Paint paint = new Paint();
+                        paint.setARGB(0x80, 0x00, 0x00, 0x00);
+                        mCanvas.drawRect(xPos, yPos,
+                                xPos + mCurrentSpec.mCellWidth,
+                                yPos + mCurrentSpec.mCellHeight, paint);
                     }
-
-                    mCellOutline.setState(stateSet);
-                    mCanvas.setBitmap(mBitmap);
-                    mCellOutline.setBounds(xPos, yPos, xPos+mCurrentSpec.mCellWidth, yPos+mCurrentSpec.mCellHeight);
-                    mCellOutline.draw(mCanvas);
+                    int width = overlay.getIntrinsicWidth();
+                    int height = overlay.getIntrinsicHeight();
+                    int left = (mCurrentSpec.mCellWidth - width) / 2 + xPos;
+                    int top = (mCurrentSpec.mCellHeight - height) / 2 + yPos;
+                    Rect newBounds =
+                            new Rect(left, top, left + width, top + height);
+                    overlay.setBounds(newBounds);
+                    overlay.draw(mCanvas);
                 }
+                paintSel(base + baseOffset, xPos, yPos);
+            }
 
-                private void loadImage(
-                        final int base,
-                        final int baseOffset,
-                        final IImage image,
-                        final int xPos,
-                        final int yPos) {
-                    synchronized (ImageBlock.this) {
-                        final int startBlock = mBlockNumber;
-                        final int pos = base + baseOffset;
-                        final ImageLoader.LoadedCallback r = new ImageLoader.LoadedCallback() {
-                            public void run(Bitmap b) {
-                                boolean more = false;
-                                synchronized (ImageBlock.this) {
-                                    if (startBlock != mBlockNumber) {
-//                                      Log.v(TAG, "wanted block " + mBlockNumber + " but got " + startBlock);
-                                        return;
-                                    }
+            private void repaintSelection() {
+                int count = mGallery.mAllImages.getCount();
+                int startPos = mBlockNumber * mCurrentSpec.mColumns;
+                synchronized (ImageBlock.this) {
+                    for (int i = 0; i < mCurrentSpec.mColumns; i++) {
+                        int pos = startPos + i;
 
-                                    if (mBitmap == null) {
-                                        return;
-                                    }
+                        if (pos >= count) {
+                            break;
+                        }
 
-                                    drawBitmap(image, base, baseOffset, b, xPos, yPos);
+                        int row = 0; // i / mCurrentSpec.mColumns;
+                        int col = i - (row * mCurrentSpec.mColumns);
 
-                                    int mask = (1 << baseOffset);
-                                    mRequestedMask &= ~mask;
-                                    mCompletedMask |= mask;
+                        // this is duplicated from getOrKick 
+                        // (TODO: don't duplicate this code)
+                        int spacing = mCurrentSpec.mCellSpacing;
+                        int leftSpacing = mCurrentSpec.mLeftEdgePadding;
+                        final int yPos = spacing
+                                + (row * (mCurrentSpec.mCellHeight + spacing));
+                        final int xPos = leftSpacing
+                                + (col * (mCurrentSpec.mCellWidth + spacing));
 
-                                 // Log.v(TAG, "for " + mBlockNumber + " mRequestedMask is " + String.format("%x", mRequestedMask) + " and mCompletedMask is " + String.format("%x", mCompletedMask));
-
-                                    if (mRequestedMask == 0) {
-                                        if (mIsVisible) {
-                                            postInvalidate();
-                                        }
-                                        more = true;
-                                    }
-                                }
-                                if (b != null)
-                                    b.recycle();
-
-                                if (more) {
-                                    synchronized (ImageBlockManager.this) {
-                                        ImageBlockManager.this.notify();
-                                        mWorkCounter += 1;
-                                    }
-                                }
-                                if (sDump)
-                                    ImageBlockManager.this.dump();
-                            }
-                        };
-                        mRequestedMask |= (1 << baseOffset);
-                        mLoader.getBitmap(image, pos, r, mIsVisible, false);
+                        paintSel(pos, xPos, yPos);
                     }
                 }
             }
+
+            private void paintSel(int pos, int xPos, int yPos) {
+                int[] stateSet = EMPTY_STATE_SET;
+                if (pos == mCurrentSelection && mShowSelection) {
+                    if (mCurrentSelectionPressed) {
+                        stateSet = PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
+                    } else {
+                        stateSet = ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
+                    }
+                }
+
+                mCellOutline.setState(stateSet);
+                mCanvas.setBitmap(mBitmap);
+                mCellOutline.setBounds(xPos, yPos,
+                        xPos + mCurrentSpec.mCellWidth,
+                        yPos + mCurrentSpec.mCellHeight);
+                mCellOutline.draw(mCanvas);
+            }
+
+            private void loadImage(
+                    final int base,
+                    final int baseOffset,
+                    final IImage image,
+                    final int xPos,
+                    final int yPos) {
+                synchronized (ImageBlock.this) {
+                    final int startBlock = mBlockNumber;
+                    final int pos = base + baseOffset;
+                    final ImageLoader.LoadedCallback r =
+                            new ImageLoader.LoadedCallback() {
+                        public void run(Bitmap b) {
+                            boolean more = false;
+                            synchronized (ImageBlock.this) {
+                                if (startBlock != mBlockNumber) {
+                                    return;
+                                }
+
+                                if (mBitmap == null) {
+                                    return;
+                                }
+
+                                drawBitmap(image, base, baseOffset, b, xPos,
+                                        yPos);
+
+                                int mask = (1 << baseOffset);
+                                mRequestedMask &= ~mask;
+                                mCompletedMask |= mask;
+
+                                if (mRequestedMask == 0) {
+                                    if (mIsVisible) {
+                                        postInvalidate();
+                                    }
+                                    more = true;
+                                }
+                            }
+                            if (b != null) {
+                                b.recycle();
+                            }
+
+                            if (more) {
+                                synchronized (ImageBlockManager.this) {
+                                    ImageBlockManager.this.notify();
+                                    mWorkCounter += 1;
+                                }
+                            }
+                            if (DUMP) {
+                                ImageBlockManager.this.dump();
+                            }
+                        }
+                    };
+                    mRequestedMask |= (1 << baseOffset);
+                    mLoader.getBitmap(image, pos, r, mIsVisible, false);
+                }
+            }
+        }
+    }
+
+    public void init(Handler handler) {
+        mHandler = handler;
+    }
+
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (false) {
+            canvas.drawRect(0, 0, getWidth(), getHeight(), mGridViewPaint);
+            if (Config.LOGV) {
+                Log.v(TAG, "painting background w/h " + getWidth()
+                        + " / " + getHeight());
+            }
+            return;
         }
 
-        public void init(Handler handler) {
-            mHandler = handler;
+        if (mImageBlockManager != null) {
+            mImageBlockManager.doDraw(canvas);
+            mImageBlockManager.moveDataWindow(mDirectionBiasDown, false);
         }
+    }
 
-        public void onDraw(Canvas canvas) {
-            super.onDraw(canvas);
-            if (false) {
-                canvas.drawRect(0, 0, getWidth(), getHeight(), mGridViewPaint);
-                if (Config.LOGV)
-                    Log.v(TAG, "painting background w/h " + getWidth() + " / " + getHeight());
+    @Override
+    public void computeScroll() {
+        if (mScroller != null) {
+            boolean more = mScroller.computeScrollOffset();
+            scrollTo(0, (int) mScroller.getCurrY());
+            if (more) {
+                postInvalidate();  // So we draw again
+            } else {
+                mScroller = null;
+            }
+        } else {
+            super.computeScroll();
+        }
+    }
+
+    android.graphics.Rect getRectForPosition(int pos) {
+        int row = pos / mCurrentSpec.mColumns;
+        int col = pos - (row * mCurrentSpec.mColumns);
+
+        int left = mCurrentSpec.mLeftEdgePadding
+                + (col * mCurrentSpec.mCellWidth)
+                + (Math.max(0, col - 1) * mCurrentSpec.mCellSpacing);
+        int top  = (row * mCurrentSpec.mCellHeight)
+                + (row * mCurrentSpec.mCellSpacing);
+
+        return new android.graphics.Rect(left, top,
+                left + mCurrentSpec.mCellWidth + mCurrentSpec.mCellWidth,
+                top + mCurrentSpec.mCellHeight + mCurrentSpec.mCellSpacing);
+    }
+
+    int computeSelectedIndex(android.view.MotionEvent ev) {
+        int spacing = mCurrentSpec.mCellSpacing;
+        int leftSpacing = mCurrentSpec.mLeftEdgePadding;
+
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
+        int row = (mScrollY + y - spacing)
+                / (mCurrentSpec.mCellHeight + spacing);
+        int col = Math.min(mCurrentSpec.mColumns - 1,
+                (x - leftSpacing) / (mCurrentSpec.mCellWidth + spacing));
+        return (row * mCurrentSpec.mColumns) + col;
+    }
+
+    @Override
+    public boolean onTouchEvent(android.view.MotionEvent ev) {
+        if (!mGallery.canHandleEvent()) {
+            return false;
+        }
+        
+        mGestureDetector.onTouchEvent(ev);
+        return true;
+    }
+
+    void onSelect(int index) {
+        if (index >= 0 && index < mGallery.mAllImages.getCount()) {
+            IImage img = mGallery.mAllImages.getImageAt(index);
+            if (img == null) {
                 return;
             }
 
-            if (mImageBlockManager != null) {
-                mImageBlockManager.doDraw(canvas);
-                mImageBlockManager.moveDataWindow(mDirectionBiasDown, false);
-            }
-        }
-
-        @Override
-        public void computeScroll() {
-            if (mScroller != null) {
-                boolean more = mScroller.computeScrollOffset();
-                scrollTo(0, (int)mScroller.getCurrY());
-                if (more) {
-                    postInvalidate();  // So we draw again
-                } else {
-                    mScroller = null;
-                }
+            if (mGallery.isPickIntent()) {
+                mGallery.launchCropperOrFinish(img);
             } else {
-                super.computeScroll();
-            }
-        }
-
-        private android.graphics.Rect getRectForPosition(int pos) {
-            int row = pos / mCurrentSpec.mColumns;
-            int col = pos - (row * mCurrentSpec.mColumns);
-
-            int left = mCurrentSpec.mLeftEdgePadding + (col * mCurrentSpec.mCellWidth) + (Math.max(0, col-1) * mCurrentSpec.mCellSpacing);
-            int top  = (row * mCurrentSpec.mCellHeight) + (row * mCurrentSpec.mCellSpacing);
-
-            return new android.graphics.Rect(left, top, left + mCurrentSpec.mCellWidth + mCurrentSpec.mCellWidth, top + mCurrentSpec.mCellHeight + mCurrentSpec.mCellSpacing);
-        }
-
-        int computeSelectedIndex(android.view.MotionEvent ev) {
-            int spacing = mCurrentSpec.mCellSpacing;
-            int leftSpacing = mCurrentSpec.mLeftEdgePadding;
-
-            int x = (int) ev.getX();
-            int y = (int) ev.getY();
-            int row = (mScrollY + y - spacing) / (mCurrentSpec.mCellHeight + spacing);
-            int col = Math.min(mCurrentSpec.mColumns - 1, (x - leftSpacing) / (mCurrentSpec.mCellWidth + spacing));
-            return (row * mCurrentSpec.mColumns) + col;
-        }
-
-        @Override
-        public boolean onTouchEvent(android.view.MotionEvent ev) {
-            if (!mGallery.canHandleEvent())  return false;
-            
-            mGestureDetector.onTouchEvent(ev);
-            return true;
-        }
-
-        private void onSelect(int index) {
-            if (index >= 0 && index < mGallery.mAllImages.getCount()) {
-                IImage img = mGallery.mAllImages.getImageAt(index);
-                if (img == null)
-                    return;
-
-                if (mGallery.isPickIntent()) {
-                    mGallery.launchCropperOrFinish(img);
-                } else {
-                    Uri targetUri = img.fullSizeImageUri();
-                    Uri thisUri = mGallery.getIntent().getData();
-                    if (thisUri != null) {
-                        String bucket = thisUri.getQueryParameter("bucketId");
-                        if (bucket != null) {
-                            targetUri = targetUri.buildUpon().appendQueryParameter("bucketId", bucket).build();
-                        }
+                Uri targetUri = img.fullSizeImageUri();
+                Uri thisUri = mGallery.getIntent().getData();
+                if (thisUri != null) {
+                    String bucket = thisUri.getQueryParameter("bucketId");
+                    if (bucket != null) {
+                        targetUri = targetUri.buildUpon()
+                                .appendQueryParameter("bucketId", bucket)
+                                .build();
                     }
-                    Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
+                }
+                Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
 
-                    if (img instanceof VideoObject) {
-                        intent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION,
-                                ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
-                    }
+                if (img instanceof VideoObject) {
+                    intent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION,
+                            ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+                }
 
-                    try {
-                        mContext.startActivity(intent);
-                    } catch (Exception ex) {
-                        // sdcard removal??
-                    }
+                try {
+                    mContext.startActivity(intent);
+                } catch (Exception ex) {
+                    // sdcard removal??
                 }
             }
         }
+    }
 
-        @Override
-        public void scrollBy(int x, int y) {
-            scrollTo(x, mScrollY + y);
+    @Override
+    public void scrollBy(int x, int y) {
+        scrollTo(x, mScrollY + y);
+    }
+
+    Toast mDateLocationToast;
+    int [] mDateRange = new int[2];
+
+    private String month(int month) {
+        String text = "";
+        switch (month) {
+            case 0:  text = "January";   break;
+            case 1:  text = "February";  break;
+            case 2:  text = "March";     break;
+            case 3:  text = "April";     break;
+            case 4:  text = "May";       break;
+            case 5:  text = "June";      break;
+            case 6:  text = "July";      break;
+            case 7:  text = "August";    break;
+            case 8:  text = "September"; break;
+            case 9:  text = "October";   break;
+            case 10: text = "November";  break;
+            case 11: text = "December";  break;
         }
+        return text;
+    }
 
-        Toast mDateLocationToast;
-        int [] mDateRange = new int[2];
-
-        private String month(int month) {
-            String text = "";
-            switch (month) {
-                case 0:  text = "January";   break;
-                case 1:  text = "February";  break;
-                case 2:  text = "March";     break;
-                case 3:  text = "April";     break;
-                case 4:  text = "May";       break;
-                case 5:  text = "June";      break;
-                case 6:  text = "July";      break;
-                case 7:  text = "August";    break;
-                case 8:  text = "September"; break;
-                case 9:  text = "October";   break;
-                case 10: text = "November";  break;
-                case 11: text = "December";  break;
+    Runnable mToastRunnable = new Runnable() {
+        public void run() {
+            if (mDateLocationToast != null) {
+                mDateLocationToast.cancel();
+                mDateLocationToast = null;
             }
-            return text;
-        }
 
-        Runnable mToastRunnable = new Runnable() {
-            public void run() {
-                if (mDateLocationToast != null) {
-                    mDateLocationToast.cancel();
-                    mDateLocationToast = null;
-                }
-
-                int count = mGallery.mAllImages.getCount();
-                if (count == 0)
-                    return;
-
-                GridViewSpecial.this.mImageBlockManager.getVisibleRange(mDateRange);
-
-                IImage firstImage = mGallery.mAllImages.getImageAt(mDateRange[0]);
-                int lastOffset = Math.min(count-1, mDateRange[1]);
-                IImage lastImage = mGallery.mAllImages.getImageAt(lastOffset);
-
-                GregorianCalendar dateStart = new GregorianCalendar();
-                GregorianCalendar dateEnd   = new GregorianCalendar();
-
-                dateStart.setTimeInMillis(firstImage.getDateTaken());
-                dateEnd.setTimeInMillis(lastImage.getDateTaken());
-
-                String text1 = month(dateStart.get(Calendar.MONTH)) + " " + dateStart.get(Calendar.YEAR);
-                String text2 = month(dateEnd  .get(Calendar.MONTH)) + " " + dateEnd  .get(Calendar.YEAR);
-
-                String text = text1;
-                if (!text2.equals(text1))
-                    text = text + " : " + text2;
-
-                mDateLocationToast = Toast.makeText(mContext, text, Toast.LENGTH_LONG);
-                mDateLocationToast.show();
+            int count = mGallery.mAllImages.getCount();
+            if (count == 0) {
+                return;
             }
-        };
 
-        @Override
-        public void scrollTo(int x, int y) {
-            y = Math.min(mMaxScrollY, y);
-            y = Math.max(mMinScrollY, y);
-            if (y > mScrollY)
-                mDirectionBiasDown = true;
-            else if (y < mScrollY)
-                mDirectionBiasDown = false;
-            super.scrollTo(x, y);
+            GridViewSpecial.this.mImageBlockManager.getVisibleRange(mDateRange);
+
+            IImage firstImage = mGallery.mAllImages.getImageAt(mDateRange[0]);
+            int lastOffset = Math.min(count - 1, mDateRange[1]);
+            IImage lastImage = mGallery.mAllImages.getImageAt(lastOffset);
+
+            GregorianCalendar dateStart = new GregorianCalendar();
+            GregorianCalendar dateEnd   = new GregorianCalendar();
+
+            dateStart.setTimeInMillis(firstImage.getDateTaken());
+            dateEnd.setTimeInMillis(lastImage.getDateTaken());
+
+            String text1 = month(dateStart.get(Calendar.MONTH)) + " "
+                    + dateStart.get(Calendar.YEAR);
+            String text2 = month(dateEnd.get(Calendar.MONTH)) + " "
+                    + dateEnd.get(Calendar.YEAR);
+
+            String text = text1;
+            if (!text2.equals(text1)) {
+                text = text + " : " + text2;
+            }
+
+            mDateLocationToast = Toast.makeText(mContext, text,
+                    Toast.LENGTH_LONG);
+            mDateLocationToast.show();
         }
+    };
+
+    @Override
+    public void scrollTo(int x, int y) {
+        y = Math.min(mMaxScrollY, y);
+        y = Math.max(mMinScrollY, y);
+        if (y > mScrollY) {
+            mDirectionBiasDown = true;
+        } else if (y < mScrollY) {
+            mDirectionBiasDown = false;
+        }
+        super.scrollTo(x, y);
     }
 }
diff --git a/src/com/android/camera/MenuHelper.java b/src/com/android/camera/MenuHelper.java
index 7e9116a..b572232 100644
--- a/src/com/android/camera/MenuHelper.java
+++ b/src/com/android/camera/MenuHelper.java
@@ -18,9 +18,6 @@
 
 import com.android.camera.gallery.IImage;
 
-import java.io.Closeable;
-import java.util.ArrayList;
-
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
@@ -39,51 +36,55 @@
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.SubMenu;
 import android.view.View;
-import android.view.MenuItem.OnMenuItemClickListener;
 import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import java.io.Closeable;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
 
 public class MenuHelper {
-    static private final String TAG = "MenuHelper";
+    private static final String TAG = "MenuHelper";
 
-    static public final int GENERIC_ITEM      = 1;
-    static public final int IMAGE_SAVING_ITEM = 2;
-    static public final int VIDEO_SAVING_ITEM = 3;
-    static public final int IMAGE_MODE_ITEM   = 4;
-    static public final int VIDEO_MODE_ITEM   = 5;
-    static public final int MENU_ITEM_MAX     = 5;
+    public static final int GENERIC_ITEM      = 1;
+    public static final int IMAGE_SAVING_ITEM = 2;
+    public static final int VIDEO_SAVING_ITEM = 3;
+    public static final int IMAGE_MODE_ITEM   = 4;
+    public static final int VIDEO_MODE_ITEM   = 5;
+    public static final int MENU_ITEM_MAX     = 5;
 
-    static public final int INCLUDE_ALL           = 0xFFFFFFFF;
-    static public final int INCLUDE_VIEWPLAY_MENU = (1 << 0);
-    static public final int INCLUDE_SHARE_MENU    = (1 << 1);
-    static public final int INCLUDE_SET_MENU      = (1 << 2);
-    static public final int INCLUDE_CROP_MENU     = (1 << 3);
-    static public final int INCLUDE_DELETE_MENU   = (1 << 4);
-    static public final int INCLUDE_ROTATE_MENU   = (1 << 5);
-    static public final int INCLUDE_DETAILS_MENU  = (1 << 6);
+    public static final int INCLUDE_ALL           = 0xFFFFFFFF;
+    public static final int INCLUDE_VIEWPLAY_MENU = (1 << 0);
+    public static final int INCLUDE_SHARE_MENU    = (1 << 1);
+    public static final int INCLUDE_SET_MENU      = (1 << 2);
+    public static final int INCLUDE_CROP_MENU     = (1 << 3);
+    public static final int INCLUDE_DELETE_MENU   = (1 << 4);
+    public static final int INCLUDE_ROTATE_MENU   = (1 << 5);
+    public static final int INCLUDE_DETAILS_MENU  = (1 << 6);
 
-    static public final int MENU_SWITCH_CAMERA_MODE = 0;
-    static public final int MENU_CAPTURE_PICTURE = 1;
-    static public final int MENU_CAPTURE_VIDEO = 2;
-    static public final int MENU_IMAGE_SHARE = 10;
-    static public final int MENU_IMAGE_SET = 14;
-    static public final int MENU_IMAGE_SET_WALLPAPER = 15;
-    static public final int MENU_IMAGE_SET_CONTACT = 16;
-    static public final int MENU_IMAGE_SET_MYFAVE = 17;
-    static public final int MENU_IMAGE_CROP = 18;
-    static public final int MENU_IMAGE_ROTATE = 19;
-    static public final int MENU_IMAGE_ROTATE_LEFT = 20;
-    static public final int MENU_IMAGE_ROTATE_RIGHT = 21;
-    static public final int MENU_IMAGE_TOSS = 22;
-    static public final int MENU_VIDEO_PLAY = 23;
-    static public final int MENU_VIDEO_SHARE = 24;
-    static public final int MENU_VIDEO_TOSS = 27;
+    public static final int MENU_SWITCH_CAMERA_MODE = 0;
+    public static final int MENU_CAPTURE_PICTURE = 1;
+    public static final int MENU_CAPTURE_VIDEO = 2;
+    public static final int MENU_IMAGE_SHARE = 10;
+    public static final int MENU_IMAGE_SET = 14;
+    public static final int MENU_IMAGE_SET_WALLPAPER = 15;
+    public static final int MENU_IMAGE_SET_CONTACT = 16;
+    public static final int MENU_IMAGE_SET_MYFAVE = 17;
+    public static final int MENU_IMAGE_CROP = 18;
+    public static final int MENU_IMAGE_ROTATE = 19;
+    public static final int MENU_IMAGE_ROTATE_LEFT = 20;
+    public static final int MENU_IMAGE_ROTATE_RIGHT = 21;
+    public static final int MENU_IMAGE_TOSS = 22;
+    public static final int MENU_VIDEO_PLAY = 23;
+    public static final int MENU_VIDEO_SHARE = 24;
+    public static final int MENU_VIDEO_TOSS = 27;
 
-    static private final long SHARE_FILE_LENGTH_LIMIT = 3L * 1024L * 1024L;
+    private static final long SHARE_FILE_LENGTH_LIMIT = 3L * 1024L * 1024L;
 
     public static final int NO_STORAGE_ERROR = -1;
     public static final int CANNOT_STAT_ERROR = -2;
@@ -142,6 +143,309 @@
         }
     }
 
+    private static boolean onDetailsClicked(MenuInvoker onInvoke,
+                                           final Activity activity,
+                                           final boolean isImage) {
+        onInvoke.run(new MenuCallback() {
+            public void run(Uri u, IImage image) {
+                if (image == null) {
+                    return;
+                }
+
+                AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+
+                final View d = View.inflate(activity, R.layout.detailsview,
+                        null);
+
+                ImageView imageView = (ImageView) d.findViewById(
+                        R.id.details_thumbnail_image);
+                imageView.setImageBitmap(image.miniThumbBitmap());
+
+                TextView textView = (TextView) d.findViewById(
+                        R.id.details_image_title);
+                textView.setText(image.getDisplayName());
+
+                long length = getImageFileSize(image);
+                String lengthString = lengthString = length < 0 ? ""
+                        : android.text.format.Formatter.formatFileSize(
+                        activity, length);
+                ((TextView) d
+                    .findViewById(R.id.details_file_size_value))
+                    .setText(lengthString);
+
+                int dimensionWidth = 0;
+                int dimensionHeight = 0;
+                if (isImage) {
+                    dimensionWidth = image.getWidth();
+                    dimensionHeight = image.getHeight();
+                    d.findViewById(R.id.details_duration_row)
+                            .setVisibility(View.GONE);
+                    d.findViewById(R.id.details_frame_rate_row)
+                            .setVisibility(View.GONE);
+                    d.findViewById(R.id.details_bit_rate_row)
+                            .setVisibility(View.GONE);
+                    d.findViewById(R.id.details_format_row)
+                            .setVisibility(View.GONE);
+                    d.findViewById(R.id.details_codec_row)
+                            .setVisibility(View.GONE);
+                } else {
+                    MediaMetadataRetriever retriever
+                            = new MediaMetadataRetriever();
+                    try {
+                        retriever.setMode(MediaMetadataRetriever
+                                .MODE_GET_METADATA_ONLY);
+                        retriever.setDataSource(image.getDataPath());
+                        try {
+                            dimensionWidth = Integer.parseInt(
+                                    retriever.extractMetadata(
+                                    MediaMetadataRetriever
+                                    .METADATA_KEY_VIDEO_WIDTH));
+                            dimensionHeight = Integer.parseInt(
+                                    retriever.extractMetadata(
+                                    MediaMetadataRetriever
+                                    .METADATA_KEY_VIDEO_HEIGHT));
+                        } catch (NumberFormatException e) {
+                            dimensionWidth = 0;
+                            dimensionHeight = 0;
+                        }
+
+                        try {
+                            int durationMs = Integer.parseInt(
+                                    retriever.extractMetadata(
+                                    MediaMetadataRetriever
+                                    .METADATA_KEY_DURATION));
+                            String durationValue = formatDuration(
+                                    activity, durationMs);
+                            ((TextView) d.findViewById(
+                                R.id.details_duration_value))
+                                .setText(durationValue);
+                        } catch (NumberFormatException e) {
+                            d.findViewById(
+                                    R.id.details_frame_rate_row)
+                                    .setVisibility(View.GONE);
+                        }
+
+                        try {
+                            String frameRate = String.format(
+                                    activity.getString(R.string.details_fps),
+                                    Integer.parseInt(
+                                            retriever.extractMetadata(
+                                            MediaMetadataRetriever
+                                            .METADATA_KEY_FRAME_RATE)));
+                            ((TextView) d.findViewById(
+                                R.id.details_frame_rate_value))
+                                .setText(frameRate);
+                        } catch (NumberFormatException e) {
+                            d.findViewById(
+                                    R.id.details_frame_rate_row)
+                                    .setVisibility(View.GONE);
+                        }
+
+                        try {
+                            long bitRate = Long.parseLong(
+                                    retriever.extractMetadata(
+                                    MediaMetadataRetriever
+                                    .METADATA_KEY_BIT_RATE));
+                            String bps;
+                            if (bitRate < 1000000) {
+                                bps = String.format(
+                                        activity.getString(
+                                        R.string.details_kbps),
+                                        bitRate / 1000);
+                            } else {
+                                bps = String.format(
+                                        activity.getString(
+                                        R.string.details_mbps),
+                                        ((double) bitRate) / 1000000.0);
+                            }
+                            ((TextView) d.findViewById(
+                                    R.id.details_bit_rate_value))
+                                    .setText(bps);
+                        } catch (NumberFormatException e) {
+                            d.findViewById(R.id.details_bit_rate_row)
+                                    .setVisibility(View.GONE);
+                        }
+
+                        String format = retriever.extractMetadata(
+                                MediaMetadataRetriever
+                                .METADATA_KEY_VIDEO_FORMAT);
+                        ((TextView) d.findViewById(
+                                R.id.details_format_value))
+                                .setText(format);
+
+                        String codec = retriever.extractMetadata(
+                                MediaMetadataRetriever.METADATA_KEY_CODEC);
+
+                        if (codec == null) {
+                            d.findViewById(R.id.details_codec_row).
+                                    setVisibility(View.GONE);
+                        } else {
+                            ((TextView) d.findViewById(
+                                    R.id.details_codec_value))
+                                    .setText(codec);
+                        }
+                    } catch (RuntimeException ex) {
+                        // Assume this is a corrupt video file.
+                    } finally {
+                        try {
+                            retriever.release();
+                        } catch (RuntimeException ex) {
+                            // Ignore failures while cleaning up.
+                        }
+                    }
+                }
+
+                String dimensionsString = String.format(
+                        activity.getString(R.string.details_dimension_x),
+                        dimensionWidth, dimensionHeight);
+                ((TextView) d
+                    .findViewById(R.id.details_resolution_value))
+                    .setText(dimensionsString);
+
+                String dateString = "";
+                long dateTaken = image.getDateTaken();
+                if (dateTaken != 0) {
+                    Date date = new Date(image.getDateTaken());
+                    SimpleDateFormat dateFormat = new SimpleDateFormat();
+                    dateString = dateFormat.format(date);
+
+                    ((TextView) d
+                            .findViewById(R.id.details_date_taken_value))
+                            .setText(dateString);
+                } else {
+                    d.findViewById(R.id.details_date_taken_row)
+                            .setVisibility(View.GONE);
+                }
+
+                builder.setNeutralButton(R.string.details_ok,
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog,
+                                    int which) {
+                                dialog.dismiss();
+                            }
+                        });
+
+                builder.setIcon(android.R.drawable.ic_dialog_info)
+                        .setTitle(R.string.details_panel_title)
+                        .setView(d)
+                        .show();
+            }
+        });
+        return true;
+    }
+
+    private static boolean onRotateLeftClicked(MenuInvoker onInvoke) {
+        onInvoke.run(new MenuCallback() {
+            public void run(Uri u, IImage image) {
+                if (image == null || image.isReadonly()) {
+                    return;
+                }
+                image.rotateImageBy(-90);
+            }
+        });
+        return true;
+    }
+
+    private static boolean onRotateRightClicked(MenuInvoker onInvoke) {    
+        onInvoke.run(new MenuCallback() {
+            public void run(Uri u, IImage image) {
+                if (image == null || image.isReadonly()) {
+                    return;
+                }
+                image.rotateImageBy(90);
+            }
+        });
+        return true;
+    }
+
+    private static boolean onCropClicked(MenuInvoker onInvoke,
+                                         final Activity activity) {
+        onInvoke.run(new MenuCallback() {
+            public void run(Uri u, IImage image) {
+                if (u == null) {
+                    return;
+                }
+
+                Intent cropIntent = new Intent();
+                cropIntent.setClass(activity, CropImage.class);
+                cropIntent.setData(u);
+                activity.startActivityForResult(cropIntent,
+                        RESULT_COMMON_MENU_CROP);
+            }
+        });
+        return true;
+    }
+
+    private static boolean onImageSaveClicked(MenuInvoker onInvoke,
+                                              final Activity activity) {
+        onInvoke.run(new MenuCallback() {
+            public void run(Uri u, IImage image) {
+                if (u == null || image == null) {
+                    return;
+                }
+
+                if (Config.LOGV) {
+                    Log.v(TAG, "in callback u is " + u + "; mime type is "
+                            + image.getMimeType());
+                }
+                Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
+                intent.setDataAndType(u, image.getMimeType());
+                intent.putExtra("mimeType", image.getMimeType());
+                activity.startActivity(Intent.createChooser(intent,
+                        activity.getText(R.string.setImage)));
+            }
+        });
+        return true;
+    }
+
+    private static boolean onImageShareClicked(MenuInvoker onInvoke,
+            final Activity activity, final boolean isImage) {
+        onInvoke.run(new MenuCallback() {
+            public void run(Uri u, IImage image) {
+                if (image == null) return;
+                if (!isImage && getImageFileSize(image)
+                        > SHARE_FILE_LENGTH_LIMIT) {
+                    Toast.makeText(activity,
+                            R.string.too_large_to_attach,
+                            Toast.LENGTH_LONG).show();
+                    return;
+                }
+
+                Intent intent = new Intent();
+                intent.setAction(Intent.ACTION_SEND);
+                String mimeType = image.getMimeType();
+                intent.setType(mimeType);
+                intent.putExtra(Intent.EXTRA_STREAM, u);
+                boolean isImage = ImageManager.isImageMimeType(mimeType);
+                try {
+                    activity.startActivity(Intent.createChooser(intent,
+                            activity.getText(isImage
+                            ? R.string.sendImage
+                            : R.string.sendVideo)));
+                } catch (android.content.ActivityNotFoundException ex) {
+                    Toast.makeText(activity, isImage
+                            ? R.string.no_way_to_share_image
+                            : R.string.no_way_to_share_video,
+                            Toast.LENGTH_SHORT).show();
+                }
+            }
+        });
+        return true;
+    }
+
+    private static boolean onViewPlayClicked(MenuInvoker onInvoke,
+            final Activity activity) {
+        onInvoke.run(new MenuCallback() {
+            public void run(Uri uri, IImage image) {
+                if (image != null) {
+                    Intent intent = new Intent(Intent.ACTION_VIEW,
+                            image.fullSizeImageUri());
+                    activity.startActivity(intent);
+                }
+            }});
+        return true;
+    }
+
     static MenuItemsResult addImageMenuItems(
             Menu menu,
             int inclusions,
@@ -150,305 +454,101 @@
             final Handler handler,
             final Runnable onDelete,
             final MenuInvoker onInvoke) {
-        final ArrayList<MenuItem> requiresWriteAccessItems = new ArrayList<MenuItem>();
-        final ArrayList<MenuItem> requiresNoDrmAccessItems = new ArrayList<MenuItem>();
+        final ArrayList<MenuItem> requiresWriteAccessItems =
+                new ArrayList<MenuItem>();
+        final ArrayList<MenuItem> requiresNoDrmAccessItems =
+                new ArrayList<MenuItem>();
 
         if (isImage && ((inclusions & INCLUDE_ROTATE_MENU) != 0)) {
-            SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM, MENU_IMAGE_ROTATE,
-                    40, R.string.rotate).setIcon(android.R.drawable.ic_menu_rotate);
+            SubMenu rotateSubmenu = menu.addSubMenu(IMAGE_SAVING_ITEM,
+                    MENU_IMAGE_ROTATE, 40, R.string.rotate)
+                    .setIcon(android.R.drawable.ic_menu_rotate);
             // Don't show the rotate submenu if the item at hand is read only
-            // since the items within the submenu won't be shown anyway.  This is
-            // really a framework bug in that it shouldn't show the submenu if
-            // the submenu has no visible items.
+            // since the items within the submenu won't be shown anyway. This
+            // is really a framework bug in that it shouldn't show the submenu
+            // if the submenu has no visible items.
             requiresWriteAccessItems.add(rotateSubmenu.getItem());
             if (rotateSubmenu != null) {
-                requiresWriteAccessItems.add(rotateSubmenu.add(0, MENU_IMAGE_ROTATE_LEFT, 50, R.string.rotate_left).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                    public boolean onMenuItemClick(MenuItem item) {
-                        onInvoke.run(new MenuCallback() {
-                            public void run(Uri u, IImage image) {
-                                if (image == null || image.isReadonly())
-                                    return;
-                                image.rotateImageBy(-90);
+                requiresWriteAccessItems.add(
+                        rotateSubmenu.add(0, MENU_IMAGE_ROTATE_LEFT, 50,
+                        R.string.rotate_left)
+                        .setOnMenuItemClickListener(
+                        new MenuItem.OnMenuItemClickListener() {
+                            public boolean onMenuItemClick(MenuItem item) {
+                                return onRotateLeftClicked(onInvoke);
                             }
-                        });
-                        return true;
-                    }
-                }).setAlphabeticShortcut('l'));
-                requiresWriteAccessItems.add(rotateSubmenu.add(0, MENU_IMAGE_ROTATE_RIGHT, 60, R.string.rotate_right).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                    public boolean onMenuItemClick(MenuItem item) {
-                        onInvoke.run(new MenuCallback() {
-                            public void run(Uri u, IImage image) {
-                                if (image == null || image.isReadonly())
-                                    return;
-
-                                image.rotateImageBy(90);
+                        }).setAlphabeticShortcut('l'));
+                requiresWriteAccessItems.add(
+                        rotateSubmenu.add(0, MENU_IMAGE_ROTATE_RIGHT, 60,
+                        R.string.rotate_right)
+                        .setOnMenuItemClickListener(
+                        new MenuItem.OnMenuItemClickListener() {
+                            public boolean onMenuItemClick(MenuItem item) {
+                                return onRotateRightClicked(onInvoke);
                             }
-                        });
-                        return true;
-                    }
-                }).setAlphabeticShortcut('r'));
+                        }).setAlphabeticShortcut('r'));
             }
         }
 
         if (isImage && ((inclusions & INCLUDE_CROP_MENU) != 0)) {
             MenuItem autoCrop = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_CROP, 73,
-                    R.string.camera_crop).setOnMenuItemClickListener(
-                            new MenuItem.OnMenuItemClickListener() {
-                public boolean onMenuItemClick(MenuItem item) {
-                    onInvoke.run(new MenuCallback() {
-                        public void run(Uri u, IImage image) {
-                            if (u == null)
-                                return;
-
-                            Intent cropIntent = new Intent();
-                            cropIntent.setClass(activity, CropImage.class);
-                            cropIntent.setData(u);
-                            activity.startActivityForResult(cropIntent, RESULT_COMMON_MENU_CROP);
+                    R.string.camera_crop);
+            autoCrop.setIcon(android.R.drawable.ic_menu_crop);
+            autoCrop.setOnMenuItemClickListener(
+                    new MenuItem.OnMenuItemClickListener() {
+                        public boolean onMenuItemClick(MenuItem item) {
+                            return onCropClicked(onInvoke, activity);
                         }
                     });
-                    return true;
-                }
-            });
-            autoCrop.setIcon(android.R.drawable.ic_menu_crop);
             requiresWriteAccessItems.add(autoCrop);
         }
 
         if (isImage && ((inclusions & INCLUDE_SET_MENU) != 0)) {
-            MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75, R.string.camera_set);
+            MenuItem setMenu = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SET, 75,
+                    R.string.camera_set);
             setMenu.setIcon(android.R.drawable.ic_menu_set_as);
-
-            setMenu.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                public boolean onMenuItemClick(MenuItem item) {
-                    onInvoke.run(new MenuCallback() {
-                        public void run(Uri u, IImage image) {
-                            if (u == null || image == null)
-                                return;
-
-                            if (Config.LOGV)
-                                Log.v(TAG, "in callback u is " + u + "; mime type is " + image.getMimeType());
-                            Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
-                            intent.setDataAndType(u, image.getMimeType());
-                            intent.putExtra("mimeType", image.getMimeType());
-                            activity.startActivity(Intent.createChooser(intent, activity.getText(R.string.setImage)));
+            setMenu.setOnMenuItemClickListener(
+                    new MenuItem.OnMenuItemClickListener() {
+                        public boolean onMenuItemClick(MenuItem item) {
+                            return onImageSaveClicked(onInvoke, activity);
                         }
                     });
-                    return true;
-                }
-            });
         }
 
         if ((inclusions & INCLUDE_SHARE_MENU) != 0) {
-            if (Config.LOGV)
-                Log.v(TAG, ">>>>> add share");
             MenuItem item1 = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_SHARE, 10,
                     R.string.camera_share).setOnMenuItemClickListener(
                     new MenuItem.OnMenuItemClickListener() {
-                public boolean onMenuItemClick(MenuItem item) {
-                    onInvoke.run(new MenuCallback() {
-                        public void run(Uri u, IImage image) {
-                            if (image == null) return;
-                            if (!isImage && getImageFileSize(image) > SHARE_FILE_LENGTH_LIMIT ) {
-                                Toast.makeText(activity,
-                                        R.string.too_large_to_attach, Toast.LENGTH_LONG).show();
-                                return;
-                            }
-
-                            Intent intent = new Intent();
-                            intent.setAction(Intent.ACTION_SEND);
-                            String mimeType = image.getMimeType();
-                            intent.setType(mimeType);
-                            intent.putExtra(Intent.EXTRA_STREAM, u);
-                            boolean isImage = ImageManager.isImageMimeType(mimeType);
-                            try {
-                                activity.startActivity(Intent.createChooser(intent,
-                                        activity.getText(
-                                                isImage ? R.string.sendImage : R.string.sendVideo)));
-                            } catch (android.content.ActivityNotFoundException ex) {
-                                Toast.makeText(activity,
-                                        isImage ? R.string.no_way_to_share_image
-                                                : R.string.no_way_to_share_video,
-                                                Toast.LENGTH_SHORT).show();
-                            }
+                        public boolean onMenuItemClick(MenuItem item) {
+                            return onImageShareClicked(onInvoke, activity,
+                                    isImage);
                         }
                     });
-                    return true;
-                }
-            });
             item1.setIcon(android.R.drawable.ic_menu_share);
             MenuItem item = item1;
             requiresNoDrmAccessItems.add(item);
         }
 
         if ((inclusions & INCLUDE_DELETE_MENU) != 0) {
-            MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS, 70, R.string.camera_toss);
+            MenuItem deleteItem = menu.add(IMAGE_SAVING_ITEM, MENU_IMAGE_TOSS,
+                    70, R.string.camera_toss);
             requiresWriteAccessItems.add(deleteItem);
-            deleteItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                public boolean onMenuItemClick(MenuItem item) {
-                    deleteImpl(activity, onDelete, isImage);
-                    return true;
-                }
-            })
-            .setAlphabeticShortcut('d')
-            .setIcon(android.R.drawable.ic_menu_delete);
+            deleteItem.setOnMenuItemClickListener(
+                    new MenuItem.OnMenuItemClickListener() {
+                        public boolean onMenuItemClick(MenuItem item) {
+                            deleteImpl(activity, onDelete, isImage);
+                            return true;
+                        }
+                    })
+                    .setAlphabeticShortcut('d')
+                    .setIcon(android.R.drawable.ic_menu_delete);
         }
 
         if ((inclusions & INCLUDE_DETAILS_MENU) != 0) {
-            MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            MenuItem detailsMenu = menu.add(0, 0, 80, R.string.details)
+            .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                 public boolean onMenuItemClick(MenuItem item) {
-                    onInvoke.run(new MenuCallback() {
-                        public void run(Uri u, IImage image) {
-                            if (image == null)
-                                return;
-
-                            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
-
-                            final View d = View.inflate(activity, R.layout.detailsview, null);
-
-                            ImageView imageView = (ImageView) d.findViewById(R.id.details_thumbnail_image);
-                            imageView.setImageBitmap(image.miniThumbBitmap());
-
-                            TextView textView = (TextView) d.findViewById(R.id.details_image_title);
-                            textView.setText(image.getDisplayName());
-
-                            long length = getImageFileSize(image);
-                            String lengthString = lengthString = length < 0 ? ""
-                                    : android.text.format.Formatter.formatFileSize(activity, length);
-                            ((TextView)d.findViewById(R.id.details_file_size_value))
-                                .setText(lengthString);
-
-                            int dimensionWidth = 0;
-                            int dimensionHeight = 0;
-                            if (isImage) {
-                                dimensionWidth = image.getWidth();
-                                dimensionHeight = image.getHeight();
-                                d.findViewById(R.id.details_duration_row).setVisibility(View.GONE);
-                                d.findViewById(R.id.details_frame_rate_row).setVisibility(View.GONE);
-                                d.findViewById(R.id.details_bit_rate_row).setVisibility(View.GONE);
-                                d.findViewById(R.id.details_format_row).setVisibility(View.GONE);
-                                d.findViewById(R.id.details_codec_row).setVisibility(View.GONE);
-                            } else {
-                                MediaMetadataRetriever retriever = new MediaMetadataRetriever();
-                                try {
-                                    retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
-                                    retriever.setDataSource(image.getDataPath());
-                                    try {
-                                        dimensionWidth = Integer.parseInt(
-                                                retriever.extractMetadata(
-                                                MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
-                                        dimensionHeight = Integer.parseInt(
-                                                retriever.extractMetadata(
-                                                MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
-                                    } catch (NumberFormatException e) {
-                                        dimensionWidth = 0;
-                                        dimensionHeight = 0;
-                                    }
-
-                                    try {
-                                        int durationMs = Integer.parseInt(retriever.extractMetadata(
-                                                MediaMetadataRetriever.METADATA_KEY_DURATION));
-                                        String durationValue = formatDuration(
-                                                activity, durationMs);
-                                        ((TextView)d.findViewById(R.id.details_duration_value))
-                                            .setText(durationValue);
-                                    } catch (NumberFormatException e) {
-                                        d.findViewById(R.id.details_frame_rate_row)
-                                        .setVisibility(View.GONE);
-                                    }
-
-                                    try {
-                                        String frame_rate = String.format(
-                                                activity.getString(R.string.details_fps),
-                                                Integer.parseInt(
-                                                        retriever.extractMetadata(
-                                                                MediaMetadataRetriever.METADATA_KEY_FRAME_RATE)));
-                                        ((TextView)d.findViewById(R.id.details_frame_rate_value))
-                                            .setText(frame_rate);
-                                    } catch (NumberFormatException e) {
-                                        d.findViewById(R.id.details_frame_rate_row)
-                                        .setVisibility(View.GONE);
-                                    }
-
-                                    try {
-                                        long bitRate = Long.parseLong(retriever.extractMetadata(
-                                                MediaMetadataRetriever.METADATA_KEY_BIT_RATE));
-                                        String bps;
-                                        if (bitRate < 1000000) {
-                                            bps = String.format(
-                                                    activity.getString(R.string.details_kbps),
-                                                    bitRate / 1000);
-                                        } else {
-                                            bps = String.format(
-                                                    activity.getString(R.string.details_mbps),
-                                                    ((double) bitRate) / 1000000.0);
-                                        }
-                                        ((TextView)d.findViewById(R.id.details_bit_rate_value))
-                                                .setText(bps);
-                                    } catch (NumberFormatException e) {
-                                        d.findViewById(R.id.details_bit_rate_row)
-                                                .setVisibility(View.GONE);
-                                    }
-
-                                    String format = retriever.extractMetadata(
-                                            MediaMetadataRetriever.METADATA_KEY_VIDEO_FORMAT);
-                                    ((TextView)d.findViewById(R.id.details_format_value))
-                                        .setText(format);
-
-                                    String codec = retriever.extractMetadata(
-                                                MediaMetadataRetriever.METADATA_KEY_CODEC);
-
-                                    if (codec == null) {
-                                        d.findViewById(R.id.details_codec_row).
-                                            setVisibility(View.GONE);
-                                    } else {
-                                        ((TextView)d.findViewById(R.id.details_codec_value))
-                                            .setText(codec);
-                                    }
-                                } catch(RuntimeException ex) {
-                                    // Assume this is a corrupt video file.
-                                } finally {
-                                    try {
-                                        retriever.release();
-                                    } catch (RuntimeException ex) {
-                                        // Ignore failures while cleaning up.
-                                    }
-                                }
-                            }
-
-                            String dimensionsString = String.format(
-                                    activity.getString(R.string.details_dimension_x),
-                                    dimensionWidth, dimensionHeight);
-                            ((TextView)d.findViewById(R.id.details_resolution_value))
-                                .setText(dimensionsString);
-
-                            String dateString = "";
-                            long dateTaken = image.getDateTaken();
-                            if (dateTaken != 0) {
-                                java.util.Date date = new java.util.Date(image.getDateTaken());
-                                java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat();
-                                dateString = dateFormat.format(date);
-
-                                ((TextView)d.findViewById(R.id.details_date_taken_value))
-                                    .setText(dateString);
-                            } else {
-                                d.findViewById(R.id.details_date_taken_row)
-                                    .setVisibility(View.GONE);
-                            }
-
-                            builder.setNeutralButton(R.string.details_ok,
-                                    new DialogInterface.OnClickListener() {
-                                    public void onClick(DialogInterface dialog, int which) {
-                                        dialog.dismiss();
-                                    }
-                                });
-
-                            builder.setIcon(android.R.drawable.ic_dialog_info)
-                                .setTitle(R.string.details_panel_title)
-                                .setView(d)
-                                .show();
-
-                        }
-                    });
-                    return true;
+                    return onDetailsClicked(onInvoke, activity, isImage);
                 }
             });
             detailsMenu.setIcon(R.drawable.ic_menu_view_details);
@@ -456,17 +556,10 @@
 
         if ((!isImage) && ((inclusions & INCLUDE_VIEWPLAY_MENU) != 0)) {
             menu.add(VIDEO_SAVING_ITEM, MENU_VIDEO_PLAY, 0, R.string.video_play)
-                .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                .setOnMenuItemClickListener(
+                new MenuItem.OnMenuItemClickListener() {
                 public boolean onMenuItemClick(MenuItem item) {
-                    onInvoke.run(new MenuCallback() {
-                        public void run(Uri uri, IImage image) {
-                            if (image != null) {
-                                Intent intent = new Intent(Intent.ACTION_VIEW,
-                                        image.fullSizeImageUri());
-                                activity.startActivity(intent);
-                            }
-                        }});
-                    return true;
+                    return onViewPlayClicked(onInvoke, activity);
                 }
             });
         }
@@ -474,29 +567,33 @@
 
         return new MenuItemsResult() {
             public void gettingReadyToOpen(Menu menu, IImage image) {
-                // protect against null here.  this isn't strictly speaking required
-                // but if a client app isn't handling sdcard removal properly it
-                // could happen
+                // protect against null here.  this isn't strictly speaking
+                // required but if a client app isn't handling sdcard removal
+                // properly it could happen
                 if (image == null) {
                     return;
                 }
                 boolean readOnly = image.isReadonly();
                 boolean isDrm = image.isDrm();
-                if (Config.LOGV)
+                if (Config.LOGV) {
                     Log.v(TAG, "readOnly: " + readOnly + "; drm: " + isDrm);
-                for (MenuItem item: requiresWriteAccessItems) {
-                    if (Config.LOGV)
-                        Log.v(TAG, "item is " + item.toString());
-                      item.setVisible(!readOnly);
-                      item.setEnabled(!readOnly);
                 }
-                for (MenuItem item: requiresNoDrmAccessItems) {
-                    if (Config.LOGV)
+                for (MenuItem item : requiresWriteAccessItems) {
+                    if (Config.LOGV) {
                         Log.v(TAG, "item is " + item.toString());
-                      item.setVisible(!isDrm);
-                      item.setEnabled(!isDrm);
+                    }
+                    item.setVisible(!readOnly);
+                    item.setEnabled(!readOnly);
+                }
+                for (MenuItem item : requiresNoDrmAccessItems) {
+                    if (Config.LOGV) {
+                        Log.v(TAG, "item is " + item.toString());
+                    }
+                    item.setVisible(!isDrm);
+                    item.setEnabled(!isDrm);
                 }
             }
+        
             public void aboutToCall(MenuItem menu, IImage image) {
             }
         };
@@ -510,17 +607,22 @@
         deleteImpl(activity, onDelete, false);
     }
 
-    static void deleteImage(Activity activity, Runnable onDelete, IImage image) {
+    static void deleteImage(Activity activity, Runnable onDelete,
+            IImage image) {
         if (image != null) {
             deleteImpl(activity, onDelete, ImageManager.isImage(image));
         }
     }
 
-    private static void deleteImpl(Activity activity, final Runnable onDelete, boolean isPhoto) {
-        boolean confirm = android.preference.PreferenceManager.getDefaultSharedPreferences(activity).getBoolean("pref_gallery_confirm_delete_key", true);
+    private static void deleteImpl(Activity activity, final Runnable onDelete,
+            boolean isPhoto) {
+        boolean confirm = android.preference.PreferenceManager
+                .getDefaultSharedPreferences(activity)
+                .getBoolean("pref_gallery_confirm_delete_key", true);
         if (!confirm) {
-            if (onDelete != null)
+            if (onDelete != null) {
                 onDelete.run();
+            }
         } else {
             displayDeleteDialog(activity, onDelete, isPhoto);
         }
@@ -528,45 +630,55 @@
 
     public static void displayDeleteDialog(Activity activity,
             final Runnable onDelete, boolean isPhoto) {
-        android.app.AlertDialog.Builder b = new android.app.AlertDialog.Builder(activity);
+        android.app.AlertDialog.Builder b =
+                new android.app.AlertDialog.Builder(activity);
         b.setIcon(android.R.drawable.ic_dialog_alert);
         b.setTitle(R.string.confirm_delete_title);
-        b.setMessage(isPhoto? R.string.confirm_delete_message
+        b.setMessage(isPhoto
+                ? R.string.confirm_delete_message
                 : R.string.confirm_delete_video_message);
-        b.setPositiveButton(android.R.string.ok, new android.content.DialogInterface.OnClickListener() {
-            public void onClick(android.content.DialogInterface v, int x) {
-                if (onDelete != null)
-                    onDelete.run();
-            }
-        });
-        b.setNegativeButton(android.R.string.cancel, new android.content.DialogInterface.OnClickListener() {
-            public void onClick(android.content.DialogInterface v, int x) {
-
-            }
-        });
+        b.setPositiveButton(android.R.string.ok,
+                new android.content.DialogInterface.OnClickListener() {
+                    public void onClick(android.content.DialogInterface v,
+                                        int x) {
+                        if (onDelete != null) {
+                            onDelete.run();
+                        }
+                    }
+                });
+        b.setNegativeButton(android.R.string.cancel,
+                new android.content.DialogInterface.OnClickListener() {
+                    public void onClick(android.content.DialogInterface v,
+                                        int x) {
+                    }
+                });
         b.create().show();
     }
 
     static void addSwitchModeMenuItem(Menu menu, final Activity activity,
             final boolean switchToVideo) {
-        int group = switchToVideo ? MenuHelper.IMAGE_MODE_ITEM : MenuHelper.VIDEO_MODE_ITEM;
-        int labelId = switchToVideo ? R.string.switch_to_video_lable
+        int group = switchToVideo
+                ? MenuHelper.IMAGE_MODE_ITEM
+                : MenuHelper.VIDEO_MODE_ITEM;
+        int labelId = switchToVideo
+                ? R.string.switch_to_video_lable
                 : R.string.switch_to_camera_lable;
-        int iconId = switchToVideo ? R.drawable.ic_menu_camera_video_view
+        int iconId = switchToVideo
+                ? R.drawable.ic_menu_camera_video_view
                 : android.R.drawable.ic_menu_camera;
-        MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0,
-                labelId).setOnMenuItemClickListener(
-                        new OnMenuItemClickListener() {
-            public boolean onMenuItemClick(MenuItem item) {
-                String action = switchToVideo ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
-                        : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
-                Intent intent = new Intent(action);
-                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
-                activity.startActivity(intent);
-                return true;
-             }
-        });
+        MenuItem item = menu.add(group, MENU_SWITCH_CAMERA_MODE, 0, labelId)
+                .setOnMenuItemClickListener(new OnMenuItemClickListener() {
+                    public boolean onMenuItemClick(MenuItem item) {
+                        String action = switchToVideo
+                                ? MediaStore.INTENT_ACTION_VIDEO_CAMERA
+                                : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
+                        Intent intent = new Intent(action);
+                        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                        intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+                        activity.startActivity(intent);
+                        return true;
+                     }
+                });
         item.setIcon(iconId);
     }
 
@@ -581,7 +693,8 @@
     }
 
     static void gotoCameraImageGallery(Activity activity) {
-        gotoGallery(activity, R.string.gallery_camera_bucket_name, ImageManager.INCLUDE_IMAGES);
+        gotoGallery(activity, R.string.gallery_camera_bucket_name,
+                ImageManager.INCLUDE_IMAGES);
     }
 
     static void gotoCameraVideoGallery(Activity activity) {
@@ -589,19 +702,24 @@
                 ImageManager.INCLUDE_VIDEOS);
     }
 
-    static private void gotoGallery(Activity activity, int windowTitleId, int mediaTypes) {
-        Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("bucketId",
+    private static void gotoGallery(Activity activity, int windowTitleId,
+            int mediaTypes) {
+        Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon()
+                .appendQueryParameter("bucketId",
                 ImageManager.CAMERA_IMAGE_BUCKET_ID).build();
         Intent intent = new Intent(Intent.ACTION_VIEW, target);
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         intent.putExtra("windowTitle", activity.getString(windowTitleId));
         intent.putExtra("mediaTypes", mediaTypes);
-        // Request unspecified so that we match the current camera orientation rather than
-        // matching the "flip orientation" preference.
+
+        // Request unspecified so that we match the current camera orientation
+        // rather than matching the "flip orientation" preference.
         // Disabled because people don't care for it. Also it's
-        // not as compelling now that we have implemented have quick orientation flipping.
+        // not as compelling now that we have implemented have quick orientation
+        // flipping.
         // intent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION,
-        //        android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+        //         android.content.pm.ActivityInfo
+        //         .SCREEN_ORIENTATION_UNSPECIFIED);
         try {
             activity.startActivity(intent);
         } catch (ActivityNotFoundException e) {
@@ -611,38 +729,38 @@
 
     static void addCapturePictureMenuItems(Menu menu, final Activity activity) {
         menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture)
-            .setOnMenuItemClickListener(
-                 new MenuItem.OnMenuItemClickListener() {
-                     public boolean onMenuItemClick(MenuItem item) {
-                        Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+                .setOnMenuItemClickListener(
+                new MenuItem.OnMenuItemClickListener() {
+                    public boolean onMenuItemClick(MenuItem item) {
+                        Intent intent = new Intent(
+                                MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
                         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                         try {
-                               activity.startActivity(intent);
+                            activity.startActivity(intent);
                         } catch (android.content.ActivityNotFoundException e) {
                             // Ignore exception
                         }
-                return true;
-            }
-        })
-        .setIcon(android.R.drawable.ic_menu_camera);
+                        return true;
+                    }
+                }).setIcon(android.R.drawable.ic_menu_camera);
     }
 
     static void addCaptureVideoMenuItems(Menu menu, final Activity activity) {
         menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video)
-            .setOnMenuItemClickListener(
-                 new MenuItem.OnMenuItemClickListener() {
-                     public boolean onMenuItemClick(MenuItem item) {
-                         Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
-                         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                         try {
-                             activity.startActivity(intent);
-                         } catch (android.content.ActivityNotFoundException e) {
-                             // Ignore exception
-                         }
-                return true;
-            }
-        })
-        .setIcon(R.drawable.ic_menu_camera_video_view);
+                .setOnMenuItemClickListener(
+                new MenuItem.OnMenuItemClickListener() {
+                    public boolean onMenuItemClick(MenuItem item) {
+                        Intent intent = new Intent(
+                                MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+                        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                        try {
+                            activity.startActivity(intent);
+                        } catch (android.content.ActivityNotFoundException e) {
+                            // Ignore exception
+                        }
+                        return true;
+                    }
+                }).setIcon(R.drawable.ic_menu_camera_video_view);
     }
 
     static void addCaptureMenuItems(Menu menu, final Activity activity) {
@@ -650,48 +768,61 @@
         addCaptureVideoMenuItems(menu, activity);
     }
 
-    static MenuItem addFlipOrientation(Menu menu, final Activity activity, final SharedPreferences prefs) {
+    private static boolean onFlipOrientationClicked(Activity activity,
+            SharedPreferences prefs) {
+        // Check what our actual orientation is
+        int current = activity.getResources().getConfiguration().orientation;
+        int newOrientation = android.content.pm.ActivityInfo
+                .SCREEN_ORIENTATION_LANDSCAPE;
+        if (current == Configuration.ORIENTATION_LANDSCAPE) {
+            newOrientation = android.content.pm.ActivityInfo
+                    .SCREEN_ORIENTATION_UNSPECIFIED;
+        }
+        SharedPreferences.Editor editor = prefs.edit();
+        editor.putInt("nuorientation", newOrientation);
+        editor.commit();
+        requestOrientation(activity, prefs, true);
+        return true;
+    }
+
+    static MenuItem addFlipOrientation(Menu menu, final Activity activity,
+            final SharedPreferences prefs) {
         // position 41 after rotate
         // D
         return menu
-                .add(Menu.CATEGORY_SECONDARY, 304, 41, R.string.flip_orientation)
+                .add(Menu.CATEGORY_SECONDARY, 304, 41,
+                R.string.flip_orientation)
                 .setOnMenuItemClickListener(
-                        new MenuItem.OnMenuItemClickListener() {
-            public boolean onMenuItemClick(MenuItem item) {
-                // Check what our actual orientation is
-                int current = activity.getResources().getConfiguration().orientation;
-                int newOrientation = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-                if (current == Configuration.ORIENTATION_LANDSCAPE) {
-                    newOrientation = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-                }
-                SharedPreferences.Editor editor = prefs.edit();
-                editor.putInt("nuorientation", newOrientation);
-                editor.commit();
-                requestOrientation(activity, prefs, true);
-                return true;
-            }
-        })
-        .setIcon(android.R.drawable.ic_menu_always_landscape_portrait);
+                new MenuItem.OnMenuItemClickListener() {
+                    public boolean onMenuItemClick(MenuItem item) {
+                        return onFlipOrientationClicked(activity, prefs);
+                    }
+                }).setIcon(
+                android.R.drawable.ic_menu_always_landscape_portrait);
     }
 
     static void requestOrientation(Activity activity, SharedPreferences prefs) {
         requestOrientation(activity, prefs, false);
     }
 
-    static private void requestOrientation(Activity activity, SharedPreferences prefs,
-            boolean ignoreIntentExtra) {
-        // Disable orientation for now. If it is set to SCREEN_ORIENTATION_SENSOR,
-        // a duplicated orientation will be observed.
+    private static void requestOrientation(Activity activity,
+            SharedPreferences prefs, boolean ignoreIntentExtra) {
+        // Disable orientation for now. If it is set to
+        // SCREEN_ORIENTATION_SENSOR, a duplicated orientation will be observed.
 
         return;
     }
 
-    static void setFlipOrientationEnabled(Activity activity, MenuItem flipItem) {
-        int keyboard = activity.getResources().getConfiguration().hardKeyboardHidden;
-        flipItem.setEnabled(keyboard != android.content.res.Configuration.HARDKEYBOARDHIDDEN_NO);
+    static void setFlipOrientationEnabled(Activity activity,
+            MenuItem flipItem) {
+        int keyboard = activity.getResources().getConfiguration()
+                .hardKeyboardHidden;
+        flipItem.setEnabled(keyboard != android.content.res.Configuration
+                .HARDKEYBOARDHIDDEN_NO);
     }
 
-    public static String formatDuration(final Activity activity, int durationMs) {
+    public static String formatDuration(final Activity activity,
+            int durationMs) {
         int duration = durationMs / 1000;
         int h = duration / 3600;
         int m = (duration - h * 3600) / 60;
@@ -708,7 +839,7 @@
     }
 
     public static void showStorageToast(Activity activity) {
-      showStorageToast(activity, calculatePicturesRemaining());
+        showStorageToast(activity, calculatePicturesRemaining());
     }
 
     public static void showStorageToast(Activity activity, int remaining) {
@@ -735,10 +866,12 @@
             if (!ImageManager.hasStorage()) {
                 return NO_STORAGE_ERROR;
             } else {
-                String storageDirectory = Environment.getExternalStorageDirectory().toString();
+                String storageDirectory =
+                        Environment.getExternalStorageDirectory().toString();
                 StatFs stat = new StatFs(storageDirectory);
-                float remaining = ((float)stat.getAvailableBlocks() * (float)stat.getBlockSize()) / 400000F;
-                return (int)remaining;
+                float remaining = ((float) stat.getAvailableBlocks()
+                        * (float) stat.getBlockSize()) / 400000F;
+                return (int) remaining;
             }
         } catch (Exception ex) {
             // if we can't stat the filesystem then we don't know how many
@@ -748,4 +881,3 @@
         }
     }
 }
-