Merge "3252698: Make drawing target 60fps." into ics-mr1
diff --git a/res/layout/choose_widget_type.xml b/res/layout/choose_widget_type.xml
index 7da8dd1..5f1739a 100644
--- a/res/layout/choose_widget_type.xml
+++ b/res/layout/choose_widget_type.xml
@@ -27,18 +27,18 @@
             android:layout_weight="1"
             android:minHeight="48dp"
             android:text="@string/widget_type_album"/>
-    <RadioButton android:id="@+id/widget_type_shuffle"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:minHeight="48dp"
-            android:text="@string/widget_type_shuffle"/>
     <RadioButton android:id="@+id/widget_type_photo"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:minHeight="48dp"
             android:text="@string/widget_type_photo"/>
+    <RadioButton android:id="@+id/widget_type_shuffle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:minHeight="48dp"
+            android:text="@string/widget_type_shuffle"/>
     <View android:layout_width="match_parent"
             android:layout_height="1dp"
             android:layout_weight="0"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 74ba1f3..f27d82f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -75,11 +75,11 @@
     <!-- Title prompted for user to choose a video item [CHAR LIMIT=20] -->
     <string name="select_video">Select video</string>
     <!-- Title prompted for user to choose a media object [CHAR LIMIT=20] -->
-    <string name="select_item">Select item(s)</string>
+    <string name="select_item">Select item</string>
     <!-- Title prompted for user to choose an album [CHAR LIMIT=20] -->
-    <string name="select_album">Select album(s)</string>
+    <string name="select_album">Select album</string>
     <!-- Title prompted for user to choose a group [CHAR LIMIT=20] -->
-    <string name="select_group">Select group(s)</string>
+    <string name="select_group">Select group</string>
 
     <!-- Displayed in the title of the dialog for things to do with a picture
              that is to be "set as" (e.g. set as contact photo or set as wallpaper) -->
@@ -380,14 +380,14 @@
     <string name="click_import">Touch here to import</string>
 
     <!-- The label on the radio button for the widget type that shows the images randomly. [CHAR LIMIT=30]-->
-    <string name="widget_type_album">Images from an album</string>
+    <string name="widget_type_album">Choose an album</string>
     <!-- The label on the radio button for the widget type that shows the images in an album. [CHAR LIMIT=30]-->
     <string name="widget_type_shuffle">Shuffle all images</string>
     <!-- The label on the radio button for the widget type that shows only one image. [CHAR LIMIT=30]-->
     <string name="widget_type_photo">Choose an image</string>
 
     <!-- The title of the dialog for choosing the type of widget. [CHAR LIMIT=20] -->
-    <string name="widget_type">Widget type</string>
+    <string name="widget_type">Choose images</string>
 
     <!-- Title of the Android Dreams slideshow screensaver. [CHAR LIMIT=20] -->
     <string name="slideshow_dream_name">Slideshow</string>
diff --git a/src/com/android/gallery3d/app/AlbumSetDataAdapter.java b/src/com/android/gallery3d/app/AlbumSetDataAdapter.java
index 6a8e702..5318a61 100644
--- a/src/com/android/gallery3d/app/AlbumSetDataAdapter.java
+++ b/src/com/android/gallery3d/app/AlbumSetDataAdapter.java
@@ -28,7 +28,6 @@
 import com.android.gallery3d.ui.AlbumSetView;
 import com.android.gallery3d.ui.SynchronizedHandler;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -215,21 +214,6 @@
         mLoadingListener = listener;
     }
 
-    private static void getRepresentativeItems(MediaSet set, int wanted,
-            ArrayList<MediaItem> result) {
-        if (set.getMediaItemCount() > 0) {
-            result.addAll(set.getMediaItem(0, wanted));
-        }
-
-        int n = set.getSubMediaSetCount();
-        for (int i = 0; i < n && wanted > result.size(); i++) {
-            MediaSet subset = set.getSubMediaSet(i);
-            double perSet = (double) (wanted - result.size()) / (n - i);
-            int m = (int) Math.ceil(perSet);
-            getRepresentativeItems(subset, m, result);
-        }
-    }
-
     private static class UpdateInfo {
         public long version;
         public int index;
@@ -369,9 +353,8 @@
                     if (info.index != INDEX_NONE) {
                         info.item = mSource.getSubMediaSet(info.index);
                         if (info.item == null) continue;
-                        ArrayList<MediaItem> covers = new ArrayList<MediaItem>();
-                        getRepresentativeItems(info.item, MAX_COVER_COUNT, covers);
-                        info.covers = covers.toArray(new MediaItem[covers.size()]);
+                        MediaItem cover = info.item.getCoverMediaItem();
+                        info.covers = cover == null ? new MediaItem[0] : new MediaItem[] {cover};
                     }
                 }
                 executeAndWait(new UpdateContent(info));
diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java
index 6951fa3..b7e0097 100644
--- a/src/com/android/gallery3d/app/AlbumSetPage.java
+++ b/src/com/android/gallery3d/app/AlbumSetPage.java
@@ -55,7 +55,6 @@
 import com.android.gallery3d.ui.SlotView;
 import com.android.gallery3d.ui.StaticBackground;
 import com.android.gallery3d.util.Future;
-import com.android.gallery3d.util.GalleryUtils;
 
 public class AlbumSetPage extends ActivityState implements
         SelectionManager.SelectionListener, GalleryActionBar.ClusterRunner,
@@ -70,13 +69,13 @@
 
     private static final int DATA_CACHE_SIZE = 256;
     private static final int REQUEST_DO_ANIMATION = 1;
-    private static final int MSG_GOTO_MANAGE_CACHE_PAGE = 1;
 
     private boolean mIsActive = false;
     private StaticBackground mStaticBackground;
     private AlbumSetView mAlbumSetView;
 
     private MediaSet mMediaSet;
+    private String mTitle;
     private String mSubtitle;
     private boolean mShowClusterMenu;
     private int mSelectedAction;
@@ -272,6 +271,7 @@
         Context context = mActivity.getAndroidContext();
         mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false);
         mGetAlbum = data.getBoolean(Gallery.KEY_GET_ALBUM, false);
+        mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE);
         mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE);
         mEyePosition = new EyePosition(context, this);
         mDetailsSource = new MyDetailsSource();
@@ -396,7 +396,6 @@
         } else {
             mShowClusterMenu = !inAlbum;
             inflater.inflate(R.menu.albumset, menu);
-            actionBar.setTitle(null);
             MenuItem selectItem = menu.findItem(R.id.action_select);
 
             if (selectItem != null) {
@@ -414,6 +413,7 @@
                 switchCamera.setVisible(GalleryUtils.isCameraAvailable(activity));
             }
 
+            actionBar.setTitle(mTitle);
             actionBar.setSubtitle(mSubtitle);
         }
         return true;
@@ -519,7 +519,9 @@
             }
             case SelectionManager.LEAVE_SELECTION_MODE: {
                 mActionMode.finish();
-                mActivity.getGalleryActionBar().showClusterMenu(mSelectedAction, this);
+                if (mShowClusterMenu) {
+                    mActivity.getGalleryActionBar().showClusterMenu(mSelectedAction, this);
+                }
                 mRootPane.invalidate();
                 break;
             }
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
index 44b9299..ec7d161 100644
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -16,6 +16,25 @@
 
 package com.android.gallery3d.app;
 
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.ActionBar.OnMenuVisibilityListener;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.View.MeasureSpec;
+import android.widget.ShareActionProvider;
+import android.widget.Toast;
+
 import com.android.gallery3d.R;
 import com.android.gallery3d.data.DataManager;
 import com.android.gallery3d.data.MediaDetails;
@@ -41,25 +60,6 @@
 import com.android.gallery3d.ui.UserInteractionListener;
 import com.android.gallery3d.util.GalleryUtils;
 
-import android.app.ActionBar;
-import android.app.ActionBar.OnMenuVisibilityListener;
-import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.view.WindowManager;
-import android.widget.ShareActionProvider;
-import android.widget.Toast;
-
 public class PhotoPage extends ActivityState
         implements PhotoView.PhotoTapListener, FilmStripView.Listener,
         UserInteractionListener {
@@ -92,7 +92,7 @@
     private MediaSet mMediaSet;
     private Menu mMenu;
 
-    private Intent mResultIntent = new Intent();
+    private final Intent mResultIntent = new Intent();
     private int mCurrentIndex = 0;
     private Handler mHandler;
     private boolean mShowBars = true;
@@ -121,7 +121,7 @@
         }
     }
 
-    private GLView mRootPane = new GLView() {
+    private final GLView mRootPane = new GLView() {
 
         @Override
         protected void renderBackground(GLCanvas view) {
@@ -305,6 +305,11 @@
         if (!GalleryUtils.isEditorAvailable((Context) mActivity, "image/*")) {
             supportedOperations &= ~MediaObject.SUPPORT_EDIT;
         }
+        MenuItem item = mMenu.findItem(R.id.action_slideshow);
+        if (item != null) {
+            item.setVisible(mCurrentPhoto.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE);
+        }
+
         MenuExecutor.updateMenuOperation(mMenu, supportedOperations);
     }
 
@@ -417,6 +422,7 @@
             case R.id.action_slideshow: {
                 Bundle data = new Bundle();
                 data.putString(SlideshowPage.KEY_SET_PATH, mMediaSet.getPath().toString());
+                data.putString(SlideshowPage.KEY_ITEM_PATH, path.toString());
                 data.putInt(SlideshowPage.KEY_PHOTO_INDEX, currentIndex);
                 data.putBoolean(SlideshowPage.KEY_REPEAT, true);
                 mActivity.getStateManager().startStateForResult(
diff --git a/src/com/android/gallery3d/app/SlideshowDataAdapter.java b/src/com/android/gallery3d/app/SlideshowDataAdapter.java
index fb7eec8..7c934ee 100644
--- a/src/com/android/gallery3d/app/SlideshowDataAdapter.java
+++ b/src/com/android/gallery3d/app/SlideshowDataAdapter.java
@@ -16,18 +16,19 @@
 
 package com.android.gallery3d.app;
 
+import android.graphics.Bitmap;
+
 import com.android.gallery3d.app.SlideshowPage.Slide;
 import com.android.gallery3d.data.ContentListener;
 import com.android.gallery3d.data.MediaItem;
 import com.android.gallery3d.data.MediaObject;
+import com.android.gallery3d.data.Path;
 import com.android.gallery3d.util.Future;
 import com.android.gallery3d.util.FutureListener;
 import com.android.gallery3d.util.ThreadPool;
 import com.android.gallery3d.util.ThreadPool.Job;
 import com.android.gallery3d.util.ThreadPool.JobContext;
 
-import android.graphics.Bitmap;
-
 import java.util.LinkedList;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -42,6 +43,7 @@
         public void removeContentListener(ContentListener listener);
         public long reload();
         public MediaItem getMediaItem(int index);
+        public int findItemIndex(Path path, int hint);
     }
 
     private final SlideshowSource mSource;
@@ -51,6 +53,7 @@
     private boolean mIsActive = false;
     private boolean mNeedReset;
     private boolean mDataReady;
+    private Path mInitialPath;
 
     private final LinkedList<Slide> mImageQueue = new LinkedList<Slide>();
 
@@ -61,8 +64,11 @@
     private final AtomicBoolean mNeedReload = new AtomicBoolean(false);
     private final SourceListener mSourceListener = new SourceListener();
 
-    public SlideshowDataAdapter(GalleryContext context, SlideshowSource source, int index) {
+    // The index is just a hint if initialPath is set
+    public SlideshowDataAdapter(GalleryContext context, SlideshowSource source, int index,
+            Path initialPath) {
         mSource = source;
+        mInitialPath = initialPath;
         mLoadIndex = index;
         mNextOutput = index;
         mThreadPool = context.getThreadPool();
@@ -77,7 +83,12 @@
                 return null;
             }
         }
-        return mSource.getMediaItem(mLoadIndex);
+        int index = mLoadIndex;
+        if (mInitialPath != null) {
+            index = mSource.findItemIndex(mInitialPath, index);
+            mInitialPath = null;
+        }
+        return mSource.getMediaItem(index);
     }
 
     private class ReloadTask implements Job<Void> {
diff --git a/src/com/android/gallery3d/app/SlideshowPage.java b/src/com/android/gallery3d/app/SlideshowPage.java
index 5ba7fc7..629bfd7 100644
--- a/src/com/android/gallery3d/app/SlideshowPage.java
+++ b/src/com/android/gallery3d/app/SlideshowPage.java
@@ -16,18 +16,6 @@
 
 package com.android.gallery3d.app;
 
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.ContentListener;
-import com.android.gallery3d.data.MediaItem;
-import com.android.gallery3d.data.MediaObject;
-import com.android.gallery3d.data.MediaSet;
-import com.android.gallery3d.ui.GLCanvas;
-import com.android.gallery3d.ui.GLView;
-import com.android.gallery3d.ui.SlideshowView;
-import com.android.gallery3d.ui.SynchronizedHandler;
-import com.android.gallery3d.util.Future;
-import com.android.gallery3d.util.FutureListener;
-
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
@@ -39,6 +27,19 @@
 import android.os.PowerManager.WakeLock;
 import android.view.MotionEvent;
 
+import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.ContentListener;
+import com.android.gallery3d.data.MediaItem;
+import com.android.gallery3d.data.MediaObject;
+import com.android.gallery3d.data.MediaSet;
+import com.android.gallery3d.data.Path;
+import com.android.gallery3d.ui.GLCanvas;
+import com.android.gallery3d.ui.GLView;
+import com.android.gallery3d.ui.SlideshowView;
+import com.android.gallery3d.ui.SynchronizedHandler;
+import com.android.gallery3d.util.Future;
+import com.android.gallery3d.util.FutureListener;
+
 import java.util.ArrayList;
 import java.util.Random;
 
@@ -58,7 +59,9 @@
 
     public static interface Model {
         public void pause();
+
         public void resume();
+
         public Future<Slide> nextSlide(FutureListener<Slide> listener);
     }
 
@@ -81,12 +84,11 @@
     private Slide mPendingSlide = null;
     private boolean mIsActive = false;
     private WakeLock mWakeLock;
-    private Intent mResultIntent = new Intent();
+    private final Intent mResultIntent = new Intent();
 
-    private GLView mRootPane = new GLView() {
+    private final GLView mRootPane = new GLView() {
         @Override
-        protected void onLayout(
-                boolean changed, int left, int top, int right, int bottom) {
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
             mSlideshowView.layout(0, 0, right - left, bottom - top);
         }
 
@@ -108,8 +110,8 @@
     public void onCreate(Bundle data, Bundle restoreState) {
         mFlags |= (FLAG_HIDE_ACTION_BAR | FLAG_HIDE_STATUS_BAR);
 
-        PowerManager pm = (PowerManager) mActivity.getAndroidContext()
-                .getSystemService(Context.POWER_SERVICE);
+        PowerManager pm = (PowerManager) mActivity.getAndroidContext().getSystemService(
+                Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
                 | PowerManager.ON_AFTER_RELEASE, TAG);
 
@@ -142,8 +144,8 @@
 
     private void showPendingBitmap() {
         // mPendingBitmap could be null, if
-        //    1.) there is no more items
-        //    2.) mModel is paused
+        // 1.) there is no more items
+        // 2.) mModel is paused
         Slide slide = mPendingSlide;
         if (slide == null) {
             if (mIsActive) {
@@ -157,8 +159,7 @@
         setStateResult(Activity.RESULT_OK, mResultIntent
                 .putExtra(KEY_ITEM_PATH, slide.item.getPath().toString())
                 .putExtra(KEY_PHOTO_INDEX, slide.index));
-        mHandler.sendEmptyMessageDelayed(MSG_LOAD_NEXT_BITMAP,
-                SLIDESHOW_DELAY);
+        mHandler.sendEmptyMessageDelayed(MSG_LOAD_NEXT_BITMAP, SLIDESHOW_DELAY);
     }
 
     @Override
@@ -192,23 +193,21 @@
 
         // We only want to show slideshow for images only, not videos.
         String mediaPath = data.getString(KEY_SET_PATH);
-        mediaPath = FilterUtils.newFilterPath(mediaPath,
-                FilterUtils.FILTER_IMAGE_ONLY);
+        mediaPath = FilterUtils.newFilterPath(mediaPath, FilterUtils.FILTER_IMAGE_ONLY);
         MediaSet mediaSet = mActivity.getDataManager().getMediaSet(mediaPath);
 
         if (random) {
             boolean repeat = data.getBoolean(KEY_REPEAT);
-            mModel = new SlideshowDataAdapter(
-                    mActivity, new ShuffleSource(mediaSet, repeat), 0);
-            setStateResult(Activity.RESULT_OK,
-                    mResultIntent.putExtra(KEY_PHOTO_INDEX, 0));
+            mModel = new SlideshowDataAdapter(mActivity,
+                    new ShuffleSource(mediaSet, repeat), 0, null);
+            setStateResult(Activity.RESULT_OK, mResultIntent.putExtra(KEY_PHOTO_INDEX, 0));
         } else {
             int index = data.getInt(KEY_PHOTO_INDEX);
+            Path path = Path.fromString(data.getString(KEY_ITEM_PATH));
             boolean repeat = data.getBoolean(KEY_REPEAT);
-            mModel = new SlideshowDataAdapter(mActivity,
-                    new SequentialSource(mediaSet, repeat), index);
-            setStateResult(Activity.RESULT_OK,
-                    mResultIntent.putExtra(KEY_PHOTO_INDEX, index));
+            mModel = new SlideshowDataAdapter(mActivity, new SequentialSource(mediaSet, repeat),
+                    index, path);
+            setStateResult(Activity.RESULT_OK, mResultIntent.putExtra(KEY_PHOTO_INDEX, index));
         }
     }
 
@@ -236,7 +235,7 @@
         private final MediaSet mMediaSet;
         private final Random mRandom = new Random();
         private int mOrder[] = new int[0];
-        private boolean mRepeat;
+        private final boolean mRepeat;
         private long mSourceVersion = MediaSet.INVALID_DATA_VERSION;
         private int mLastIndex = -1;
 
@@ -245,6 +244,10 @@
             mRepeat = repeat;
         }
 
+        public int findItemIndex(Path path, int hint) {
+            return hint;
+        }
+
         public MediaItem getMediaItem(int index) {
             if (!mRepeat && index >= mOrder.length) return null;
             if (mOrder.length == 0) return null;
@@ -306,6 +309,10 @@
             mRepeat = repeat;
         }
 
+        public int findItemIndex(Path path, int hint) {
+            return mMediaSet.getIndexOfItem(path, hint);
+        }
+
         public MediaItem getMediaItem(int index) {
             int dataEnd = mDataStart + mData.size();
 
@@ -320,9 +327,7 @@
                 dataEnd = index + mData.size();
             }
 
-            return (index < mDataStart || index >= dataEnd)
-                    ? null
-                    : mData.get(index - mDataStart);
+            return (index < mDataStart || index >= dataEnd) ? null : mData.get(index - mDataStart);
         }
 
         public long reload() {
diff --git a/src/com/android/gallery3d/data/MediaSet.java b/src/com/android/gallery3d/data/MediaSet.java
index a54067e..5094195 100644
--- a/src/com/android/gallery3d/data/MediaSet.java
+++ b/src/com/android/gallery3d/data/MediaSet.java
@@ -71,6 +71,16 @@
         return new ArrayList<MediaItem>();
     }
 
+    public MediaItem getCoverMediaItem() {
+        ArrayList<MediaItem> items = getMediaItem(0, 1);
+        if (items.size() > 0) return items.get(0);
+        for (int i = 0, n = getSubMediaSetCount(); i < n; i++) {
+            MediaItem cover = getSubMediaSet(i).getCoverMediaItem();
+            if (cover != null) return cover;
+        }
+        return null;
+    }
+
     public int getSubMediaSetCount() {
         return 0;
     }