AlbumSetPage.java revision d208e12012152bf757c0492cd3bfc91f101294cc
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.View;
28import android.view.View.OnClickListener;
29import android.widget.Button;
30import android.widget.RelativeLayout;
31import android.widget.Toast;
32
33import com.actionbarsherlock.view.Menu;
34import com.actionbarsherlock.view.MenuInflater;
35import com.actionbarsherlock.view.MenuItem;
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.MediaObject;
41import com.android.gallery3d.data.MediaSet;
42import com.android.gallery3d.data.Path;
43import com.android.gallery3d.picasasource.PicasaSource;
44import com.android.gallery3d.settings.GallerySettings;
45import com.android.gallery3d.ui.ActionModeHandler;
46import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
47import com.android.gallery3d.ui.AlbumSetSlotRenderer;
48import com.android.gallery3d.ui.DetailsHelper;
49import com.android.gallery3d.ui.DetailsHelper.CloseListener;
50import com.android.gallery3d.ui.FadeTexture;
51import com.android.gallery3d.ui.GLCanvas;
52import com.android.gallery3d.ui.GLRoot;
53import com.android.gallery3d.ui.GLView;
54import com.android.gallery3d.ui.PreparePageFadeoutTexture;
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;
63
64public class AlbumSetPage extends ActivityState implements
65        SelectionManager.SelectionListener, GalleryActionBar.ClusterRunner,
66        EyePosition.EyePositionListener, MediaSet.SyncListener {
67    @SuppressWarnings("unused")
68    private static final String TAG = "AlbumSetPage";
69
70    private static final int MSG_PICK_ALBUM = 1;
71
72    public static final String KEY_MEDIA_PATH = "media-path";
73    public static final String KEY_SET_TITLE = "set-title";
74    public static final String KEY_SET_SUBTITLE = "set-subtitle";
75    public static final String KEY_SELECTED_CLUSTER_TYPE = "selected-cluster";
76
77    private static final int DATA_CACHE_SIZE = 256;
78    private static final int REQUEST_DO_ANIMATION = 1;
79
80    private static final int BIT_LOADING_RELOAD = 1;
81    private static final int BIT_LOADING_SYNC = 2;
82
83    private boolean mIsActive = false;
84    private SlotView mSlotView;
85    private AlbumSetSlotRenderer mAlbumSetView;
86    private Config.AlbumSetPage mConfig;
87
88    private MediaSet mMediaSet;
89    private String mTitle;
90    private String mSubtitle;
91    private boolean mShowClusterMenu;
92    private GalleryActionBar mActionBar;
93    private int mSelectedAction;
94    private Vibrator mVibrator;
95
96    protected SelectionManager mSelectionManager;
97    private AlbumSetDataLoader mAlbumSetDataAdapter;
98
99    private boolean mGetContent;
100    private boolean mGetAlbum;
101    private ActionModeHandler mActionModeHandler;
102    private DetailsHelper mDetailsHelper;
103    private MyDetailsSource mDetailsSource;
104    private boolean mShowDetails;
105    private EyePosition mEyePosition;
106    private Handler mHandler;
107
108    // The eyes' position of the user, the origin is at the center of the
109    // device and the unit is in pixels.
110    private float mX;
111    private float mY;
112    private float mZ;
113
114    private Future<Integer> mSyncTask = null;
115
116    private int mLoadingBits = 0;
117    private boolean mInitialSynced = false;
118
119    private Button mCameraButton;
120    private boolean mShowedEmptyToastForSelf = false;
121
122    @Override
123    protected int getBackgroundColorId() {
124        return R.color.albumset_background;
125    }
126
127    private final GLView mRootPane = new GLView() {
128        private final float mMatrix[] = new float[16];
129
130        @Override
131        protected void renderBackground(GLCanvas view) {
132            view.clearBuffer(getBackgroundColor());
133        }
134
135        @Override
136        protected void onLayout(
137                boolean changed, int left, int top, int right, int bottom) {
138            mEyePosition.resetPosition();
139
140            int slotViewTop = mActionBar.getHeight() + mConfig.paddingTop;
141            int slotViewBottom = bottom - top - mConfig.paddingBottom;
142            int slotViewRight = right - left;
143
144            if (mShowDetails) {
145                mDetailsHelper.layout(left, slotViewTop, right, bottom);
146            } else {
147                mAlbumSetView.setHighlightItemPath(null);
148            }
149
150            mSlotView.layout(0, slotViewTop, slotViewRight, slotViewBottom);
151        }
152
153        @Override
154        protected void render(GLCanvas canvas) {
155            canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
156            GalleryUtils.setViewPointMatrix(mMatrix,
157                    getWidth() / 2 + mX, getHeight() / 2 + mY, mZ);
158            canvas.multiplyMatrix(mMatrix, 0);
159            super.render(canvas);
160            canvas.restore();
161        }
162    };
163
164    @Override
165    public void onEyePositionChanged(float x, float y, float z) {
166        mRootPane.lockRendering();
167        mX = x;
168        mY = y;
169        mZ = z;
170        mRootPane.unlockRendering();
171        mRootPane.invalidate();
172    }
173
174    @Override
175    public void onBackPressed() {
176        if (mShowDetails) {
177            hideDetails();
178        } else if (mSelectionManager.inSelectionMode()) {
179            mSelectionManager.leaveSelectionMode();
180        } else {
181            super.onBackPressed();
182        }
183    }
184
185    private void getSlotCenter(int slotIndex, int center[]) {
186        Rect offset = new Rect();
187        mRootPane.getBoundsOf(mSlotView, offset);
188        Rect r = mSlotView.getSlotRect(slotIndex);
189        int scrollX = mSlotView.getScrollX();
190        int scrollY = mSlotView.getScrollY();
191        center[0] = offset.left + (r.left + r.right) / 2 - scrollX;
192        center[1] = offset.top + (r.top + r.bottom) / 2 - scrollY;
193    }
194
195    public void onSingleTapUp(int slotIndex) {
196        if (!mIsActive) return;
197
198        if (mSelectionManager.inSelectionMode()) {
199            MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex);
200            if (targetSet == null) return; // Content is dirty, we shall reload soon
201            mSelectionManager.toggle(targetSet.getPath());
202            mSlotView.invalidate();
203        } else {
204            // Show pressed-up animation for the single-tap.
205            mAlbumSetView.setPressedIndex(slotIndex);
206            mAlbumSetView.setPressedUp();
207            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0),
208                    FadeTexture.DURATION);
209        }
210    }
211
212    private static boolean albumShouldOpenInFilmstrip(MediaSet album) {
213        int itemCount = album.getMediaItemCount();
214        return (album.isCameraRoll() && itemCount > 0) || itemCount == 1;
215    }
216
217    WeakReference<Toast> mEmptyAlbumToast = null;
218
219    private void showEmptyAlbumToast(int toastLength) {
220        Toast toast;
221        if (mEmptyAlbumToast != null) {
222            toast = mEmptyAlbumToast.get();
223            if (toast != null) {
224                toast.show();
225                return;
226            }
227        }
228        toast = Toast.makeText(mActivity, R.string.empty_album, toastLength);
229        mEmptyAlbumToast = new WeakReference<Toast>(toast);
230        toast.show();
231    }
232
233    private void hideEmptyAlbumToast() {
234        if (mEmptyAlbumToast != null) {
235            Toast toast = mEmptyAlbumToast.get();
236            if (toast != null) toast.cancel();
237        }
238    }
239
240    private void pickAlbum(int slotIndex) {
241        if (!mIsActive) return;
242
243        MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex);
244        if (targetSet == null) return; // Content is dirty, we shall reload soon
245        if (targetSet.getTotalMediaItemCount() == 0) {
246            showEmptyAlbumToast(Toast.LENGTH_SHORT);
247            return;
248        }
249        hideEmptyAlbumToast();
250
251        String mediaPath = targetSet.getPath().toString();
252
253        Bundle data = new Bundle(getData());
254        int[] center = new int[2];
255        getSlotCenter(slotIndex, center);
256        data.putIntArray(AlbumPage.KEY_SET_CENTER, center);
257        if (mGetAlbum && targetSet.isLeafAlbum()) {
258            Activity activity = mActivity;
259            Intent result = new Intent()
260                    .putExtra(AlbumPicker.KEY_ALBUM_PATH, targetSet.getPath().toString());
261            activity.setResult(Activity.RESULT_OK, result);
262            activity.finish();
263        } else if (targetSet.getSubMediaSetCount() > 0) {
264            data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath);
265            mActivity.getStateManager().startStateForResult(
266                    AlbumSetPage.class, REQUEST_DO_ANIMATION, data);
267        } else {
268            if (!mGetContent && (targetSet.getSupportedOperations()
269                    & MediaObject.SUPPORT_IMPORT) != 0) {
270                data.putBoolean(AlbumPage.KEY_AUTO_SELECT_ALL, true);
271            } else if (!mGetContent && albumShouldOpenInFilmstrip(targetSet)) {
272                PreparePageFadeoutTexture.prepareFadeOutTexture(mActivity, mSlotView, mRootPane);
273                data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT,
274                        mSlotView.getSlotRect(slotIndex, mRootPane));
275                data.putInt(PhotoPage.KEY_INDEX_HINT, 0);
276                data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
277                        mediaPath);
278                data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP, true);
279                mActivity.getStateManager().startStateForResult(
280                        PhotoPage.class, AlbumPage.REQUEST_PHOTO, data);
281                return;
282            }
283            data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath);
284
285            // We only show cluster menu in the first AlbumPage in stack
286            boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class);
287            data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum);
288            mActivity.getStateManager().startStateForResult(
289                    AlbumPage.class, REQUEST_DO_ANIMATION, data);
290        }
291    }
292
293    private void onDown(int index) {
294        mAlbumSetView.setPressedIndex(index);
295    }
296
297    private void onUp(boolean followedByLongPress) {
298        if (followedByLongPress) {
299            // Avoid showing press-up animations for long-press.
300            mAlbumSetView.setPressedIndex(-1);
301        } else {
302            mAlbumSetView.setPressedUp();
303        }
304    }
305
306    public void onLongTap(int slotIndex) {
307        if (mGetContent || mGetAlbum) return;
308        MediaSet set = mAlbumSetDataAdapter.getMediaSet(slotIndex);
309        if (set == null) return;
310        mSelectionManager.setAutoLeaveSelectionMode(true);
311        mSelectionManager.toggle(set.getPath());
312        mSlotView.invalidate();
313    }
314
315    @Override
316    public void doCluster(int clusterType) {
317        String basePath = mMediaSet.getPath().toString();
318        String newPath = FilterUtils.switchClusterPath(basePath, clusterType);
319        Bundle data = new Bundle(getData());
320        data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath);
321        data.putInt(KEY_SELECTED_CLUSTER_TYPE, clusterType);
322        mActivity.getStateManager().switchState(this, AlbumSetPage.class, data);
323    }
324
325    @Override
326    public void onCreate(Bundle data, Bundle restoreState) {
327        super.onCreate(data, restoreState);
328        initializeViews();
329        initializeData(data);
330        Context context = mActivity.getAndroidContext();
331        mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false);
332        mGetAlbum = data.getBoolean(Gallery.KEY_GET_ALBUM, false);
333        mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE);
334        mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE);
335        mEyePosition = new EyePosition(context, this);
336        mDetailsSource = new MyDetailsSource();
337        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
338        mActionBar = mActivity.getGalleryActionBar();
339        mSelectedAction = data.getInt(AlbumSetPage.KEY_SELECTED_CLUSTER_TYPE,
340                FilterUtils.CLUSTER_BY_ALBUM);
341
342        mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
343            @Override
344            public void handleMessage(Message message) {
345                switch (message.what) {
346                    case MSG_PICK_ALBUM: {
347                        pickAlbum(message.arg1);
348                        break;
349                    }
350                    default: throw new AssertionError(message.what);
351                }
352            }
353        };
354    }
355
356    @Override
357    public void onDestroy() {
358        cleanupCameraButton();
359        super.onDestroy();
360    }
361
362    private boolean setupCameraButton() {
363        RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity)
364                .findViewById(R.id.gallery_root);
365        if (galleryRoot == null) return false;
366
367        mCameraButton = new Button(mActivity);
368        mCameraButton.setText(R.string.camera_label);
369        mCameraButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.camera_white, 0, 0);
370        mCameraButton.setOnClickListener(new OnClickListener() {
371            @Override
372            public void onClick(View arg0) {
373                GalleryUtils.startCameraActivity(mActivity);
374            }
375        });
376        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
377                RelativeLayout.LayoutParams.WRAP_CONTENT,
378                RelativeLayout.LayoutParams.WRAP_CONTENT);
379        lp.addRule(RelativeLayout.CENTER_IN_PARENT);
380        galleryRoot.addView(mCameraButton, lp);
381        return true;
382    }
383
384    private void cleanupCameraButton() {
385        if (mCameraButton == null) return;
386        RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity)
387                .findViewById(R.id.gallery_root);
388        if (galleryRoot == null) return;
389        galleryRoot.removeView(mCameraButton);
390        mCameraButton = null;
391    }
392
393    private void showCameraButton() {
394        if (mCameraButton == null && !setupCameraButton()) return;
395        mCameraButton.setVisibility(View.VISIBLE);
396    }
397
398    private void hideCameraButton() {
399        if (mCameraButton == null) return;
400        mCameraButton.setVisibility(View.GONE);
401    }
402
403    private void clearLoadingBit(int loadingBit) {
404        mLoadingBits &= ~loadingBit;
405        if (mLoadingBits == 0 && mIsActive) {
406            if (mAlbumSetDataAdapter.size() == 0) {
407                // If this is not the top of the gallery folder hierarchy,
408                // tell the parent AlbumSetPage instance to handle displaying
409                // the empty album toast, otherwise show it within this
410                // instance
411                if (mActivity.getStateManager().getStateCount() > 1) {
412                    Intent result = new Intent();
413                    result.putExtra(AlbumPage.KEY_EMPTY_ALBUM, true);
414                    setStateResult(Activity.RESULT_OK, result);
415                    mActivity.getStateManager().finishState(this);
416                } else {
417                    mShowedEmptyToastForSelf = true;
418                    showEmptyAlbumToast(Toast.LENGTH_LONG);
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            mShowClusterMenu = !inAlbum;
549            boolean selectAlbums = !inAlbum &&
550                    mActionBar.getClusterTypeAction() == FilterUtils.CLUSTER_BY_ALBUM;
551            MenuItem selectItem = menu.findItem(R.id.action_select);
552            selectItem.setTitle(activity.getString(
553                    selectAlbums ? R.string.select_album : R.string.select_group));
554
555            MenuItem cameraItem = menu.findItem(R.id.action_camera);
556            cameraItem.setVisible(GalleryUtils.isCameraAvailable(activity));
557
558            FilterUtils.setupMenuItems(mActionBar, mMediaSet.getPath(), false);
559
560            Intent helpIntent = HelpUtils.getHelpIntent(activity, R.string.help_url_gallery_main);
561
562            MenuItem helpItem = menu.findItem(R.id.action_general_help);
563            helpItem.setVisible(helpIntent != null);
564            if (helpIntent != null) helpItem.setIntent(helpIntent);
565
566            mActionBar.setTitle(mTitle);
567            mActionBar.setSubtitle(mSubtitle);
568        }
569        return true;
570    }
571
572    @Override
573    protected boolean onItemSelected(MenuItem item) {
574        Activity activity = mActivity;
575        switch (item.getItemId()) {
576            case R.id.action_cancel:
577                activity.setResult(Activity.RESULT_CANCELED);
578                activity.finish();
579                return true;
580            case R.id.action_select:
581                mSelectionManager.setAutoLeaveSelectionMode(false);
582                mSelectionManager.enterSelectionMode();
583                return true;
584            case R.id.action_details:
585                if (mAlbumSetDataAdapter.size() != 0) {
586                    if (mShowDetails) {
587                        hideDetails();
588                    } else {
589                        showDetails();
590                    }
591                } else {
592                    Toast.makeText(activity,
593                            activity.getText(R.string.no_albums_alert),
594                            Toast.LENGTH_SHORT).show();
595                }
596                return true;
597            case R.id.action_camera: {
598                GalleryUtils.startCameraActivity(activity);
599                return true;
600            }
601            case R.id.action_manage_offline: {
602                Bundle data = new Bundle();
603                String mediaPath = mActivity.getDataManager().getTopSetPath(
604                    DataManager.INCLUDE_ALL);
605                data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath);
606                mActivity.getStateManager().startState(ManageCachePage.class, data);
607                return true;
608            }
609            case R.id.action_sync_picasa_albums: {
610                PicasaSource.requestSync(activity);
611                return true;
612            }
613            case R.id.action_settings: {
614                activity.startActivity(new Intent(activity, GallerySettings.class));
615                return true;
616            }
617            default:
618                return false;
619        }
620    }
621
622    @Override
623    protected void onStateResult(int requestCode, int resultCode, Intent data) {
624        if (data != null && data.getBooleanExtra(AlbumPage.KEY_EMPTY_ALBUM, false)) {
625            showEmptyAlbumToast(Toast.LENGTH_SHORT);
626        }
627        switch (requestCode) {
628            case REQUEST_DO_ANIMATION: {
629                mSlotView.startRisingAnimation();
630            }
631        }
632    }
633
634    private String getSelectedString() {
635        int count = mSelectionManager.getSelectedCount();
636        int action = mActionBar.getClusterTypeAction();
637        int string = action == FilterUtils.CLUSTER_BY_ALBUM
638                ? R.plurals.number_of_albums_selected
639                : R.plurals.number_of_groups_selected;
640        String format = mActivity.getResources().getQuantityString(string, count);
641        return String.format(format, count);
642    }
643
644    @Override
645    public void onSelectionModeChange(int mode) {
646        switch (mode) {
647            case SelectionManager.ENTER_SELECTION_MODE: {
648                mActionBar.disableClusterMenu(true);
649                mActionModeHandler.startActionMode();
650                if (mHapticsEnabled) mVibrator.vibrate(100);
651                break;
652            }
653            case SelectionManager.LEAVE_SELECTION_MODE: {
654                mActionModeHandler.finishActionMode();
655                if (mShowClusterMenu) {
656                    mActionBar.enableClusterMenu(mSelectedAction, this);
657                }
658                mRootPane.invalidate();
659                break;
660            }
661            case SelectionManager.SELECT_ALL_MODE: {
662                mActionModeHandler.updateSupportedOperation();
663                mRootPane.invalidate();
664                break;
665            }
666        }
667    }
668
669    @Override
670    public void onSelectionChange(Path path, boolean selected) {
671        mActionModeHandler.setTitle(getSelectedString());
672        mActionModeHandler.updateSupportedOperation(path, selected);
673    }
674
675    private void hideDetails() {
676        mShowDetails = false;
677        mDetailsHelper.hide();
678        mAlbumSetView.setHighlightItemPath(null);
679        mSlotView.invalidate();
680    }
681
682    private void showDetails() {
683        mShowDetails = true;
684        if (mDetailsHelper == null) {
685            mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource);
686            mDetailsHelper.setCloseListener(new CloseListener() {
687                @Override
688                public void onClose() {
689                    hideDetails();
690                }
691            });
692        }
693        mDetailsHelper.show();
694    }
695
696    @Override
697    public void onSyncDone(final MediaSet mediaSet, final int resultCode) {
698        if (resultCode == MediaSet.SYNC_RESULT_ERROR) {
699            Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result="
700                    + resultCode);
701        }
702        ((Activity) mActivity).runOnUiThread(new Runnable() {
703            @Override
704            public void run() {
705                GLRoot root = mActivity.getGLRoot();
706                root.lockRenderThread();
707                try {
708                    if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) {
709                        mInitialSynced = true;
710                    }
711                    clearLoadingBit(BIT_LOADING_SYNC);
712                    if (resultCode == MediaSet.SYNC_RESULT_ERROR && mIsActive) {
713                        Log.w(TAG, "failed to load album set");
714                    }
715                } finally {
716                    root.unlockRenderThread();
717                }
718            }
719        });
720    }
721
722    private class MyLoadingListener implements LoadingListener {
723        @Override
724        public void onLoadingStarted() {
725            setLoadingBit(BIT_LOADING_RELOAD);
726        }
727
728        @Override
729        public void onLoadingFinished() {
730            clearLoadingBit(BIT_LOADING_RELOAD);
731        }
732    }
733
734    private class MyDetailsSource implements DetailsHelper.DetailsSource {
735        private int mIndex;
736
737        @Override
738        public int size() {
739            return mAlbumSetDataAdapter.size();
740        }
741
742        @Override
743        public int setIndex() {
744            Path id = mSelectionManager.getSelected(false).get(0);
745            mIndex = mAlbumSetDataAdapter.findSet(id);
746            return mIndex;
747        }
748
749        @Override
750        public MediaDetails getDetails() {
751            MediaObject item = mAlbumSetDataAdapter.getMediaSet(mIndex);
752            if (item != null) {
753                mAlbumSetView.setHighlightItemPath(item.getPath());
754                return item.getDetails();
755            } else {
756                return null;
757            }
758        }
759    }
760}
761