AlbumSetPage.java revision 05da3f520eacb9219964b6ed57ef37846d889fd7
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.gallery3d.app;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.graphics.Rect;
23import android.os.Bundle;
24import android.os.Handler;
25import android.os.Message;
26import android.os.Vibrator;
27import android.view.Menu;
28import android.view.MenuInflater;
29import android.view.MenuItem;
30import android.view.View;
31import android.view.View.OnClickListener;
32import android.widget.Button;
33import android.widget.RelativeLayout;
34import android.widget.Toast;
35
36import com.android.gallery3d.R;
37import com.android.gallery3d.common.Utils;
38import com.android.gallery3d.data.DataManager;
39import com.android.gallery3d.data.MediaDetails;
40import com.android.gallery3d.data.MediaItem;
41import com.android.gallery3d.data.MediaObject;
42import com.android.gallery3d.data.MediaSet;
43import com.android.gallery3d.data.Path;
44import com.android.gallery3d.picasasource.PicasaSource;
45import com.android.gallery3d.settings.GallerySettings;
46import com.android.gallery3d.ui.ActionModeHandler;
47import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
48import com.android.gallery3d.ui.AlbumSetSlotRenderer;
49import com.android.gallery3d.ui.DetailsHelper;
50import com.android.gallery3d.ui.DetailsHelper.CloseListener;
51import com.android.gallery3d.ui.FadeTexture;
52import com.android.gallery3d.ui.GLCanvas;
53import com.android.gallery3d.ui.GLRoot;
54import com.android.gallery3d.ui.GLView;
55import com.android.gallery3d.ui.SelectionManager;
56import com.android.gallery3d.ui.SlotView;
57import com.android.gallery3d.ui.SynchronizedHandler;
58import com.android.gallery3d.util.Future;
59import com.android.gallery3d.util.GalleryUtils;
60import com.android.gallery3d.util.HelpUtils;
61
62import java.lang.ref.WeakReference;
63import java.util.ArrayList;
64
65public class AlbumSetPage extends ActivityState implements
66        SelectionManager.SelectionListener, GalleryActionBar.ClusterRunner,
67        EyePosition.EyePositionListener, MediaSet.SyncListener {
68    @SuppressWarnings("unused")
69    private static final String TAG = "AlbumSetPage";
70
71    private static final int MSG_PICK_ALBUM = 1;
72
73    public static final String KEY_MEDIA_PATH = "media-path";
74    public static final String KEY_SET_TITLE = "set-title";
75    public static final String KEY_SET_SUBTITLE = "set-subtitle";
76    public static final String KEY_SELECTED_CLUSTER_TYPE = "selected-cluster";
77
78    private static final int DATA_CACHE_SIZE = 256;
79    private static final int REQUEST_DO_ANIMATION = 1;
80
81    private static final int BIT_LOADING_RELOAD = 1;
82    private static final int BIT_LOADING_SYNC = 2;
83
84    private boolean mIsActive = false;
85    private SlotView mSlotView;
86    private AlbumSetSlotRenderer mAlbumSetView;
87    private Config.AlbumSetPage mConfig;
88
89    private MediaSet mMediaSet;
90    private String mTitle;
91    private String mSubtitle;
92    private boolean mShowClusterMenu;
93    private GalleryActionBar mActionBar;
94    private int mSelectedAction;
95    private Vibrator mVibrator;
96
97    protected SelectionManager mSelectionManager;
98    private AlbumSetDataLoader mAlbumSetDataAdapter;
99
100    private boolean mGetContent;
101    private boolean mGetAlbum;
102    private ActionModeHandler mActionModeHandler;
103    private DetailsHelper mDetailsHelper;
104    private MyDetailsSource mDetailsSource;
105    private boolean mShowDetails;
106    private EyePosition mEyePosition;
107    private Handler mHandler;
108
109    // The eyes' position of the user, the origin is at the center of the
110    // device and the unit is in pixels.
111    private float mX;
112    private float mY;
113    private float mZ;
114
115    private Future<Integer> mSyncTask = null;
116
117    private int mLoadingBits = 0;
118    private boolean mInitialSynced = false;
119
120    private Button mCameraButton;
121    private boolean mShowedEmptyToastForSelf = false;
122
123    @Override
124    protected int getBackgroundColorId() {
125        return R.color.albumset_background;
126    }
127
128    private final GLView mRootPane = new GLView() {
129        private final float mMatrix[] = new float[16];
130
131        @Override
132        protected void onLayout(
133                boolean changed, int left, int top, int right, int bottom) {
134            mEyePosition.resetPosition();
135
136            int slotViewTop = mActionBar.getHeight() + mConfig.paddingTop;
137            int slotViewBottom = bottom - top - mConfig.paddingBottom;
138            int slotViewRight = right - left;
139
140            if (mShowDetails) {
141                mDetailsHelper.layout(left, slotViewTop, right, bottom);
142            } else {
143                mAlbumSetView.setHighlightItemPath(null);
144            }
145
146            mSlotView.layout(0, slotViewTop, slotViewRight, slotViewBottom);
147        }
148
149        @Override
150        protected void render(GLCanvas canvas) {
151            canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
152            GalleryUtils.setViewPointMatrix(mMatrix,
153                    getWidth() / 2 + mX, getHeight() / 2 + mY, mZ);
154            canvas.multiplyMatrix(mMatrix, 0);
155            super.render(canvas);
156            canvas.restore();
157        }
158    };
159
160    @Override
161    public void onEyePositionChanged(float x, float y, float z) {
162        mRootPane.lockRendering();
163        mX = x;
164        mY = y;
165        mZ = z;
166        mRootPane.unlockRendering();
167        mRootPane.invalidate();
168    }
169
170    @Override
171    public void onBackPressed() {
172        if (mShowDetails) {
173            hideDetails();
174        } else if (mSelectionManager.inSelectionMode()) {
175            mSelectionManager.leaveSelectionMode();
176        } else {
177            super.onBackPressed();
178        }
179    }
180
181    private void getSlotCenter(int slotIndex, int center[]) {
182        Rect offset = new Rect();
183        mRootPane.getBoundsOf(mSlotView, offset);
184        Rect r = mSlotView.getSlotRect(slotIndex);
185        int scrollX = mSlotView.getScrollX();
186        int scrollY = mSlotView.getScrollY();
187        center[0] = offset.left + (r.left + r.right) / 2 - scrollX;
188        center[1] = offset.top + (r.top + r.bottom) / 2 - scrollY;
189    }
190
191    public void onSingleTapUp(int slotIndex) {
192        if (!mIsActive) return;
193
194        if (mSelectionManager.inSelectionMode()) {
195            MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex);
196            if (targetSet == null) return; // Content is dirty, we shall reload soon
197            mSelectionManager.toggle(targetSet.getPath());
198            mSlotView.invalidate();
199        } else {
200            // Show pressed-up animation for the single-tap.
201            mAlbumSetView.setPressedIndex(slotIndex);
202            mAlbumSetView.setPressedUp();
203            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0),
204                    FadeTexture.DURATION);
205        }
206    }
207
208    private static boolean albumShouldOpenInFilmstrip(MediaSet album) {
209        int itemCount = album.getMediaItemCount();
210        ArrayList<MediaItem> list = (itemCount == 1) ? album.getMediaItem(0, 1) : null;
211        // open in film strip only if there's one item in the album and the item exists
212        return (list != null && !list.isEmpty());
213    }
214
215    WeakReference<Toast> mEmptyAlbumToast = null;
216
217    private void showEmptyAlbumToast(int toastLength) {
218        Toast toast;
219        if (mEmptyAlbumToast != null) {
220            toast = mEmptyAlbumToast.get();
221            if (toast != null) {
222                toast.show();
223                return;
224            }
225        }
226        toast = Toast.makeText(mActivity, R.string.empty_album, toastLength);
227        mEmptyAlbumToast = new WeakReference<Toast>(toast);
228        toast.show();
229    }
230
231    private void hideEmptyAlbumToast() {
232        if (mEmptyAlbumToast != null) {
233            Toast toast = mEmptyAlbumToast.get();
234            if (toast != null) toast.cancel();
235        }
236    }
237
238    private void pickAlbum(int slotIndex) {
239        if (!mIsActive) return;
240
241        MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex);
242        if (targetSet == null) return; // Content is dirty, we shall reload soon
243        if (targetSet.getTotalMediaItemCount() == 0) {
244            showEmptyAlbumToast(Toast.LENGTH_SHORT);
245            return;
246        }
247        hideEmptyAlbumToast();
248
249        String mediaPath = targetSet.getPath().toString();
250
251        Bundle data = new Bundle(getData());
252        int[] center = new int[2];
253        getSlotCenter(slotIndex, center);
254        data.putIntArray(AlbumPage.KEY_SET_CENTER, center);
255        if (mGetAlbum && targetSet.isLeafAlbum()) {
256            Activity activity = mActivity;
257            Intent result = new Intent()
258                    .putExtra(AlbumPicker.KEY_ALBUM_PATH, targetSet.getPath().toString());
259            activity.setResult(Activity.RESULT_OK, result);
260            activity.finish();
261        } else if (targetSet.getSubMediaSetCount() > 0) {
262            data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath);
263            mActivity.getStateManager().startStateForResult(
264                    AlbumSetPage.class, REQUEST_DO_ANIMATION, data);
265        } else {
266            if (!mGetContent && (targetSet.getSupportedOperations()
267                    & MediaObject.SUPPORT_IMPORT) != 0) {
268                data.putBoolean(AlbumPage.KEY_AUTO_SELECT_ALL, true);
269            } else if (!mGetContent && albumShouldOpenInFilmstrip(targetSet)) {
270                data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT,
271                        mSlotView.getSlotRect(slotIndex, mRootPane));
272                data.putInt(PhotoPage.KEY_INDEX_HINT, 0);
273                data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
274                        mediaPath);
275                data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP, true);
276                data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, targetSet.isCameraRoll());
277                mActivity.getStateManager().startStateForResult(
278                        PhotoPage.class, AlbumPage.REQUEST_PHOTO, data);
279                return;
280            }
281            data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath);
282
283            // We only show cluster menu in the first AlbumPage in stack
284            boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class);
285            data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum);
286            mActivity.getStateManager().startStateForResult(
287                    AlbumPage.class, REQUEST_DO_ANIMATION, data);
288        }
289    }
290
291    private void onDown(int index) {
292        mAlbumSetView.setPressedIndex(index);
293    }
294
295    private void onUp(boolean followedByLongPress) {
296        if (followedByLongPress) {
297            // Avoid showing press-up animations for long-press.
298            mAlbumSetView.setPressedIndex(-1);
299        } else {
300            mAlbumSetView.setPressedUp();
301        }
302    }
303
304    public void onLongTap(int slotIndex) {
305        if (mGetContent || mGetAlbum) return;
306        MediaSet set = mAlbumSetDataAdapter.getMediaSet(slotIndex);
307        if (set == null) return;
308        mSelectionManager.setAutoLeaveSelectionMode(true);
309        mSelectionManager.toggle(set.getPath());
310        mSlotView.invalidate();
311    }
312
313    @Override
314    public void doCluster(int clusterType) {
315        String basePath = mMediaSet.getPath().toString();
316        String newPath = FilterUtils.switchClusterPath(basePath, clusterType);
317        Bundle data = new Bundle(getData());
318        data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath);
319        data.putInt(KEY_SELECTED_CLUSTER_TYPE, clusterType);
320        mActivity.getStateManager().switchState(this, AlbumSetPage.class, data);
321    }
322
323    @Override
324    public void onCreate(Bundle data, Bundle restoreState) {
325        super.onCreate(data, restoreState);
326        initializeViews();
327        initializeData(data);
328        Context context = mActivity.getAndroidContext();
329        mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false);
330        mGetAlbum = data.getBoolean(Gallery.KEY_GET_ALBUM, false);
331        mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE);
332        mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE);
333        mEyePosition = new EyePosition(context, this);
334        mDetailsSource = new MyDetailsSource();
335        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
336        mActionBar = mActivity.getGalleryActionBar();
337        mSelectedAction = data.getInt(AlbumSetPage.KEY_SELECTED_CLUSTER_TYPE,
338                FilterUtils.CLUSTER_BY_ALBUM);
339
340        mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
341            @Override
342            public void handleMessage(Message message) {
343                switch (message.what) {
344                    case MSG_PICK_ALBUM: {
345                        pickAlbum(message.arg1);
346                        break;
347                    }
348                    default: throw new AssertionError(message.what);
349                }
350            }
351        };
352    }
353
354    @Override
355    public void onDestroy() {
356        cleanupCameraButton();
357        super.onDestroy();
358    }
359
360    private boolean setupCameraButton() {
361        if (!GalleryUtils.isCameraAvailable(mActivity)) return false;
362        RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity)
363                .findViewById(R.id.gallery_root);
364        if (galleryRoot == null) return false;
365
366        mCameraButton = new Button(mActivity);
367        mCameraButton.setText(R.string.camera_label);
368        mCameraButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.frame_overlay_gallery_camera, 0, 0);
369        mCameraButton.setOnClickListener(new OnClickListener() {
370            @Override
371            public void onClick(View arg0) {
372                GalleryUtils.startCameraActivity(mActivity);
373            }
374        });
375        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
376                RelativeLayout.LayoutParams.WRAP_CONTENT,
377                RelativeLayout.LayoutParams.WRAP_CONTENT);
378        lp.addRule(RelativeLayout.CENTER_IN_PARENT);
379        galleryRoot.addView(mCameraButton, lp);
380        return true;
381    }
382
383    private void cleanupCameraButton() {
384        if (mCameraButton == null) return;
385        RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity)
386                .findViewById(R.id.gallery_root);
387        if (galleryRoot == null) return;
388        galleryRoot.removeView(mCameraButton);
389        mCameraButton = null;
390    }
391
392    private void showCameraButton() {
393        if (mCameraButton == null && !setupCameraButton()) return;
394        mCameraButton.setVisibility(View.VISIBLE);
395    }
396
397    private void hideCameraButton() {
398        if (mCameraButton == null) return;
399        mCameraButton.setVisibility(View.GONE);
400    }
401
402    private void clearLoadingBit(int loadingBit) {
403        mLoadingBits &= ~loadingBit;
404        if (mLoadingBits == 0 && mIsActive) {
405            if (mAlbumSetDataAdapter.size() == 0) {
406                // If this is not the top of the gallery folder hierarchy,
407                // tell the parent AlbumSetPage instance to handle displaying
408                // the empty album toast, otherwise show it within this
409                // instance
410                if (mActivity.getStateManager().getStateCount() > 1) {
411                    Intent result = new Intent();
412                    result.putExtra(AlbumPage.KEY_EMPTY_ALBUM, true);
413                    setStateResult(Activity.RESULT_OK, result);
414                    mActivity.getStateManager().finishState(this);
415                } else {
416                    mShowedEmptyToastForSelf = true;
417                    showEmptyAlbumToast(Toast.LENGTH_LONG);
418                    mSlotView.invalidate();
419                    showCameraButton();
420                }
421                return;
422            }
423        }
424        // Hide the empty album toast if we are in the root instance of
425        // AlbumSetPage and the album is no longer empty (for instance,
426        // after a sync is completed and web albums have been synced)
427        if (mShowedEmptyToastForSelf) {
428            mShowedEmptyToastForSelf = false;
429            hideEmptyAlbumToast();
430            hideCameraButton();
431        }
432    }
433
434    private void setLoadingBit(int loadingBit) {
435        mLoadingBits |= loadingBit;
436    }
437
438    @Override
439    public void onPause() {
440        super.onPause();
441        mIsActive = false;
442        mActionModeHandler.pause();
443        mAlbumSetDataAdapter.pause();
444        mAlbumSetView.pause();
445        mEyePosition.pause();
446        DetailsHelper.pause();
447        // Call disableClusterMenu to avoid receiving callback after paused.
448        // Don't hide menu here otherwise the list menu will disappear earlier than
449        // the action bar, which is janky and unwanted behavior.
450        mActionBar.disableClusterMenu(false);
451        if (mSyncTask != null) {
452            mSyncTask.cancel();
453            mSyncTask = null;
454            clearLoadingBit(BIT_LOADING_SYNC);
455        }
456    }
457
458    @Override
459    public void onResume() {
460        super.onResume();
461        mIsActive = true;
462        setContentPane(mRootPane);
463
464        // Set the reload bit here to prevent it exit this page in clearLoadingBit().
465        setLoadingBit(BIT_LOADING_RELOAD);
466        mAlbumSetDataAdapter.resume();
467
468        mAlbumSetView.resume();
469        mEyePosition.resume();
470        mActionModeHandler.resume();
471        if (mShowClusterMenu) {
472            mActionBar.enableClusterMenu(mSelectedAction, this);
473        }
474        if (!mInitialSynced) {
475            setLoadingBit(BIT_LOADING_SYNC);
476            mSyncTask = mMediaSet.requestSync(AlbumSetPage.this);
477        }
478    }
479
480    private void initializeData(Bundle data) {
481        String mediaPath = data.getString(AlbumSetPage.KEY_MEDIA_PATH);
482        mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath);
483        mSelectionManager.setSourceMediaSet(mMediaSet);
484        mAlbumSetDataAdapter = new AlbumSetDataLoader(
485                mActivity, mMediaSet, DATA_CACHE_SIZE);
486        mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener());
487        mAlbumSetView.setModel(mAlbumSetDataAdapter);
488    }
489
490    private void initializeViews() {
491        mSelectionManager = new SelectionManager(mActivity, true);
492        mSelectionManager.setSelectionListener(this);
493
494        mConfig = Config.AlbumSetPage.get(mActivity);
495        mSlotView = new SlotView(mActivity, mConfig.slotViewSpec);
496        mAlbumSetView = new AlbumSetSlotRenderer(
497                mActivity, mSelectionManager, mSlotView, mConfig.labelSpec,
498                mConfig.placeholderColor);
499        mSlotView.setSlotRenderer(mAlbumSetView);
500        mSlotView.setListener(new SlotView.SimpleListener() {
501            @Override
502            public void onDown(int index) {
503                AlbumSetPage.this.onDown(index);
504            }
505
506            @Override
507            public void onUp(boolean followedByLongPress) {
508                AlbumSetPage.this.onUp(followedByLongPress);
509            }
510
511            @Override
512            public void onSingleTapUp(int slotIndex) {
513                AlbumSetPage.this.onSingleTapUp(slotIndex);
514            }
515
516            @Override
517            public void onLongTap(int slotIndex) {
518                AlbumSetPage.this.onLongTap(slotIndex);
519            }
520        });
521
522        mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager);
523        mActionModeHandler.setActionModeListener(new ActionModeListener() {
524            @Override
525            public boolean onActionItemClicked(MenuItem item) {
526                return onItemSelected(item);
527            }
528        });
529        mRootPane.addComponent(mSlotView);
530    }
531
532    @Override
533    protected boolean onCreateActionBar(Menu menu) {
534        Activity activity = mActivity;
535        final boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class);
536        MenuInflater inflater = getSupportMenuInflater();
537
538        if (mGetContent) {
539            inflater.inflate(R.menu.pickup, menu);
540            int typeBits = mData.getInt(
541                    Gallery.KEY_TYPE_BITS, DataManager.INCLUDE_IMAGE);
542            mActionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits));
543        } else  if (mGetAlbum) {
544            inflater.inflate(R.menu.pickup, menu);
545            mActionBar.setTitle(R.string.select_album);
546        } else {
547            inflater.inflate(R.menu.albumset, menu);
548            boolean wasShowingClusterMenu = mShowClusterMenu;
549            mShowClusterMenu = !inAlbum;
550            boolean selectAlbums = !inAlbum &&
551                    mActionBar.getClusterTypeAction() == FilterUtils.CLUSTER_BY_ALBUM;
552            MenuItem selectItem = menu.findItem(R.id.action_select);
553            selectItem.setTitle(activity.getString(
554                    selectAlbums ? R.string.select_album : R.string.select_group));
555
556            MenuItem cameraItem = menu.findItem(R.id.action_camera);
557            cameraItem.setVisible(GalleryUtils.isCameraAvailable(activity));
558
559            FilterUtils.setupMenuItems(mActionBar, mMediaSet.getPath(), false);
560
561            Intent helpIntent = HelpUtils.getHelpIntent(activity, R.string.help_url_gallery_main);
562
563            MenuItem helpItem = menu.findItem(R.id.action_general_help);
564            helpItem.setVisible(helpIntent != null);
565            if (helpIntent != null) helpItem.setIntent(helpIntent);
566
567            mActionBar.setTitle(mTitle);
568            mActionBar.setSubtitle(mSubtitle);
569            if (mShowClusterMenu != wasShowingClusterMenu) {
570                if (mShowClusterMenu) {
571                    mActionBar.enableClusterMenu(mSelectedAction, this);
572                } else {
573                    mActionBar.disableClusterMenu(true);
574                }
575            }
576        }
577        return true;
578    }
579
580    @Override
581    protected boolean onItemSelected(MenuItem item) {
582        Activity activity = mActivity;
583        switch (item.getItemId()) {
584            case R.id.action_cancel:
585                activity.setResult(Activity.RESULT_CANCELED);
586                activity.finish();
587                return true;
588            case R.id.action_select:
589                mSelectionManager.setAutoLeaveSelectionMode(false);
590                mSelectionManager.enterSelectionMode();
591                return true;
592            case R.id.action_details:
593                if (mAlbumSetDataAdapter.size() != 0) {
594                    if (mShowDetails) {
595                        hideDetails();
596                    } else {
597                        showDetails();
598                    }
599                } else {
600                    Toast.makeText(activity,
601                            activity.getText(R.string.no_albums_alert),
602                            Toast.LENGTH_SHORT).show();
603                }
604                return true;
605            case R.id.action_camera: {
606                GalleryUtils.startCameraActivity(activity);
607                return true;
608            }
609            case R.id.action_manage_offline: {
610                Bundle data = new Bundle();
611                String mediaPath = mActivity.getDataManager().getTopSetPath(
612                    DataManager.INCLUDE_ALL);
613                data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath);
614                mActivity.getStateManager().startState(ManageCachePage.class, data);
615                return true;
616            }
617            case R.id.action_sync_picasa_albums: {
618                PicasaSource.requestSync(activity);
619                return true;
620            }
621            case R.id.action_settings: {
622                activity.startActivity(new Intent(activity, GallerySettings.class));
623                return true;
624            }
625            default:
626                return false;
627        }
628    }
629
630    @Override
631    protected void onStateResult(int requestCode, int resultCode, Intent data) {
632        if (data != null && data.getBooleanExtra(AlbumPage.KEY_EMPTY_ALBUM, false)) {
633            showEmptyAlbumToast(Toast.LENGTH_SHORT);
634        }
635        switch (requestCode) {
636            case REQUEST_DO_ANIMATION: {
637                mSlotView.startRisingAnimation();
638            }
639        }
640    }
641
642    private String getSelectedString() {
643        int count = mSelectionManager.getSelectedCount();
644        int action = mActionBar.getClusterTypeAction();
645        int string = action == FilterUtils.CLUSTER_BY_ALBUM
646                ? R.plurals.number_of_albums_selected
647                : R.plurals.number_of_groups_selected;
648        String format = mActivity.getResources().getQuantityString(string, count);
649        return String.format(format, count);
650    }
651
652    @Override
653    public void onSelectionModeChange(int mode) {
654        switch (mode) {
655            case SelectionManager.ENTER_SELECTION_MODE: {
656                mActionBar.disableClusterMenu(true);
657                mActionModeHandler.startActionMode();
658                if (mHapticsEnabled) mVibrator.vibrate(100);
659                break;
660            }
661            case SelectionManager.LEAVE_SELECTION_MODE: {
662                mActionModeHandler.finishActionMode();
663                if (mShowClusterMenu) {
664                    mActionBar.enableClusterMenu(mSelectedAction, this);
665                }
666                mRootPane.invalidate();
667                break;
668            }
669            case SelectionManager.SELECT_ALL_MODE: {
670                mActionModeHandler.updateSupportedOperation();
671                mRootPane.invalidate();
672                break;
673            }
674        }
675    }
676
677    @Override
678    public void onSelectionChange(Path path, boolean selected) {
679        mActionModeHandler.setTitle(getSelectedString());
680        mActionModeHandler.updateSupportedOperation(path, selected);
681    }
682
683    private void hideDetails() {
684        mShowDetails = false;
685        mDetailsHelper.hide();
686        mAlbumSetView.setHighlightItemPath(null);
687        mSlotView.invalidate();
688    }
689
690    private void showDetails() {
691        mShowDetails = true;
692        if (mDetailsHelper == null) {
693            mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource);
694            mDetailsHelper.setCloseListener(new CloseListener() {
695                @Override
696                public void onClose() {
697                    hideDetails();
698                }
699            });
700        }
701        mDetailsHelper.show();
702    }
703
704    @Override
705    public void onSyncDone(final MediaSet mediaSet, final int resultCode) {
706        if (resultCode == MediaSet.SYNC_RESULT_ERROR) {
707            Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result="
708                    + resultCode);
709        }
710        ((Activity) mActivity).runOnUiThread(new Runnable() {
711            @Override
712            public void run() {
713                GLRoot root = mActivity.getGLRoot();
714                root.lockRenderThread();
715                try {
716                    if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) {
717                        mInitialSynced = true;
718                    }
719                    clearLoadingBit(BIT_LOADING_SYNC);
720                    if (resultCode == MediaSet.SYNC_RESULT_ERROR && mIsActive) {
721                        Log.w(TAG, "failed to load album set");
722                    }
723                } finally {
724                    root.unlockRenderThread();
725                }
726            }
727        });
728    }
729
730    private class MyLoadingListener implements LoadingListener {
731        @Override
732        public void onLoadingStarted() {
733            setLoadingBit(BIT_LOADING_RELOAD);
734        }
735
736        @Override
737        public void onLoadingFinished(boolean loadingFailed) {
738            clearLoadingBit(BIT_LOADING_RELOAD);
739        }
740    }
741
742    private class MyDetailsSource implements DetailsHelper.DetailsSource {
743        private int mIndex;
744
745        @Override
746        public int size() {
747            return mAlbumSetDataAdapter.size();
748        }
749
750        @Override
751        public int setIndex() {
752            Path id = mSelectionManager.getSelected(false).get(0);
753            mIndex = mAlbumSetDataAdapter.findSet(id);
754            return mIndex;
755        }
756
757        @Override
758        public MediaDetails getDetails() {
759            MediaObject item = mAlbumSetDataAdapter.getMediaSet(mIndex);
760            if (item != null) {
761                mAlbumSetView.setHighlightItemPath(item.getPath());
762                return item.getDetails();
763            } else {
764                return null;
765            }
766        }
767    }
768}
769