OSDN Git Service

Stay in AlbumPage when dismissing a popup from AP
[android-x86/packages-apps-Gallery2.git] / src / com / android / gallery3d / app / AlbumPage.java
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
17 package com.android.gallery3d.app;
18
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.graphics.Rect;
23 import android.net.Uri;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.os.Vibrator;
28 import android.provider.MediaStore;
29 import android.view.Menu;
30 import android.view.MenuInflater;
31 import android.view.MenuItem;
32 import android.widget.Toast;
33
34 import com.android.gallery3d.R;
35 import com.android.gallery3d.common.Utils;
36 import com.android.gallery3d.data.DataManager;
37 import com.android.gallery3d.data.MediaDetails;
38 import com.android.gallery3d.data.MediaItem;
39 import com.android.gallery3d.data.MediaObject;
40 import com.android.gallery3d.data.MediaSet;
41 import com.android.gallery3d.data.MtpDevice;
42 import com.android.gallery3d.data.Path;
43 import com.android.gallery3d.ui.ActionModeHandler;
44 import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
45 import com.android.gallery3d.ui.AlbumSlotRenderer;
46 import com.android.gallery3d.ui.DetailsHelper;
47 import com.android.gallery3d.ui.DetailsHelper.CloseListener;
48 import com.android.gallery3d.ui.FadeTexture;
49 import com.android.gallery3d.ui.GLCanvas;
50 import com.android.gallery3d.ui.GLRoot;
51 import com.android.gallery3d.ui.GLView;
52 import com.android.gallery3d.ui.PhotoFallbackEffect;
53 import com.android.gallery3d.ui.RelativePosition;
54 import com.android.gallery3d.ui.SelectionManager;
55 import com.android.gallery3d.ui.SlotView;
56 import com.android.gallery3d.ui.SynchronizedHandler;
57 import com.android.gallery3d.util.Future;
58 import com.android.gallery3d.util.GalleryUtils;
59 import com.android.gallery3d.util.MediaSetUtils;
60
61 public class AlbumPage extends ActivityState implements GalleryActionBar.ClusterRunner,
62         SelectionManager.SelectionListener, MediaSet.SyncListener, GalleryActionBar.OnAlbumModeSelectedListener {
63     @SuppressWarnings("unused")
64     private static final String TAG = "AlbumPage";
65
66     public static final String KEY_MEDIA_PATH = "media-path";
67     public static final String KEY_PARENT_MEDIA_PATH = "parent-media-path";
68     public static final String KEY_SET_CENTER = "set-center";
69     public static final String KEY_AUTO_SELECT_ALL = "auto-select-all";
70     public static final String KEY_SHOW_CLUSTER_MENU = "cluster-menu";
71     public static final String KEY_EMPTY_ALBUM = "empty-album";
72     public static final String KEY_RESUME_ANIMATION = "resume_animation";
73
74     private static final int REQUEST_SLIDESHOW = 1;
75     public static final int REQUEST_PHOTO = 2;
76     private static final int REQUEST_DO_ANIMATION = 3;
77
78     private static final int BIT_LOADING_RELOAD = 1;
79     private static final int BIT_LOADING_SYNC = 2;
80
81     private static final float USER_DISTANCE_METER = 0.3f;
82
83     private boolean mIsActive = false;
84     private AlbumSlotRenderer mAlbumView;
85     private Path mMediaSetPath;
86     private String mParentMediaSetString;
87     private SlotView mSlotView;
88
89     private AlbumDataLoader mAlbumDataAdapter;
90
91     protected SelectionManager mSelectionManager;
92     private Vibrator mVibrator;
93
94     private boolean mGetContent;
95     private boolean mShowClusterMenu;
96
97     private ActionModeHandler mActionModeHandler;
98     private int mFocusIndex = 0;
99     private DetailsHelper mDetailsHelper;
100     private MyDetailsSource mDetailsSource;
101     private MediaSet mMediaSet;
102     private boolean mShowDetails;
103     private float mUserDistance; // in pixel
104     private Future<Integer> mSyncTask = null;
105     private boolean mLaunchedFromPhotoPage;
106     private boolean mInCameraApp;
107     private boolean mInCameraAndWantQuitOnPause;
108
109     private int mLoadingBits = 0;
110     private boolean mInitialSynced = false;
111     private RelativePosition mOpenCenter = new RelativePosition();
112
113     private Handler mHandler;
114     private static final int MSG_PICK_PHOTO = 0;
115
116     private PhotoFallbackEffect mResumeEffect;
117     private PhotoFallbackEffect.PositionProvider mPositionProvider =
118             new PhotoFallbackEffect.PositionProvider() {
119         @Override
120         public Rect getPosition(int index) {
121             Rect rect = mSlotView.getSlotRect(index);
122             Rect bounds = mSlotView.bounds();
123             rect.offset(bounds.left - mSlotView.getScrollX(),
124                     bounds.top - mSlotView.getScrollY());
125             return rect;
126         }
127
128         @Override
129         public int getItemIndex(Path path) {
130             int start = mSlotView.getVisibleStart();
131             int end = mSlotView.getVisibleEnd();
132             for (int i = start; i < end; ++i) {
133                 MediaItem item = mAlbumDataAdapter.get(i);
134                 if (item != null && item.getPath() == path) return i;
135             }
136             return -1;
137         }
138     };
139
140     @Override
141     protected int getBackgroundColorId() {
142         return R.color.album_background;
143     }
144
145     private final GLView mRootPane = new GLView() {
146         private final float mMatrix[] = new float[16];
147
148         @Override
149         protected void onLayout(
150                 boolean changed, int left, int top, int right, int bottom) {
151
152             int slotViewTop = mActivity.getGalleryActionBar().getHeight();
153             int slotViewBottom = bottom - top;
154             int slotViewRight = right - left;
155
156             if (mShowDetails) {
157                 mDetailsHelper.layout(left, slotViewTop, right, bottom);
158             } else {
159                 mAlbumView.setHighlightItemPath(null);
160             }
161
162             // Set the mSlotView as a reference point to the open animation
163             mOpenCenter.setReferencePosition(0, slotViewTop);
164             mSlotView.layout(0, slotViewTop, slotViewRight, slotViewBottom);
165             GalleryUtils.setViewPointMatrix(mMatrix,
166                     (right - left) / 2, (bottom - top) / 2, -mUserDistance);
167         }
168
169         @Override
170         protected void render(GLCanvas canvas) {
171             canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
172             canvas.multiplyMatrix(mMatrix, 0);
173             super.render(canvas);
174
175             if (mResumeEffect != null) {
176                 boolean more = mResumeEffect.draw(canvas);
177                 if (!more) {
178                     mResumeEffect = null;
179                     mAlbumView.setSlotFilter(null);
180                 }
181                 // We want to render one more time even when no more effect
182                 // required. So that the animated thumbnails could be draw
183                 // with declarations in super.render().
184                 invalidate();
185             }
186             canvas.restore();
187         }
188     };
189
190     // This are the transitions we want:
191     //
192     // +--------+           +------------+    +-------+    +----------+
193     // | Camera |---------->| Fullscreen |--->| Album |--->| AlbumSet |
194     // |  View  | thumbnail |   Photo    | up | Page  | up |   Page   |
195     // +--------+           +------------+    +-------+    +----------+
196     //     ^                      |               |            ^  |
197     //     |                      |               |            |  |         close
198     //     +----------back--------+               +----back----+  +--back->  app
199     //
200     @Override
201     protected void onBackPressed() {
202         if (mShowDetails) {
203             hideDetails();
204         } else if (mSelectionManager.inSelectionMode()) {
205             mSelectionManager.leaveSelectionMode();
206         } else {
207             if(mLaunchedFromPhotoPage) {
208                 mActivity.getTransitionStore().putIfNotPresent(
209                         PhotoPage.KEY_ALBUMPAGE_TRANSITION,
210                         PhotoPage.MSG_ALBUMPAGE_RESUMED);
211             }
212             // TODO: fix this regression
213             // mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
214             if (mInCameraApp) {
215                 super.onBackPressed();
216             } else {
217                 onUpPressed();
218             }
219         }
220     }
221
222     private void onUpPressed() {
223         if (mInCameraApp) {
224             GalleryUtils.startGalleryActivity(mActivity);
225         } else if (mActivity.getStateManager().getStateCount() > 1) {
226             super.onBackPressed();
227         } else if (mParentMediaSetString != null) {
228             Bundle data = new Bundle(getData());
229             data.putString(AlbumSetPage.KEY_MEDIA_PATH, mParentMediaSetString);
230             mActivity.getStateManager().switchState(
231                     this, AlbumSetPage.class, data);
232         }
233     }
234
235     private void onDown(int index) {
236         mAlbumView.setPressedIndex(index);
237     }
238
239     private void onUp(boolean followedByLongPress) {
240         if (followedByLongPress) {
241             // Avoid showing press-up animations for long-press.
242             mAlbumView.setPressedIndex(-1);
243         } else {
244             mAlbumView.setPressedUp();
245         }
246     }
247
248     private void onSingleTapUp(int slotIndex) {
249         if (!mIsActive) return;
250
251         if (mSelectionManager.inSelectionMode()) {
252             MediaItem item = mAlbumDataAdapter.get(slotIndex);
253             if (item == null) return; // Item not ready yet, ignore the click
254             mSelectionManager.toggle(item.getPath());
255             mSlotView.invalidate();
256         } else {
257             // Render transition in pressed state
258             mAlbumView.setPressedIndex(slotIndex);
259             mAlbumView.setPressedUp();
260             mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_PHOTO, slotIndex, 0),
261                     FadeTexture.DURATION);
262         }
263     }
264
265     private void pickPhoto(int slotIndex) {
266         pickPhoto(slotIndex, false);
267     }
268
269     private void pickPhoto(int slotIndex, boolean startInFilmstrip) {
270         if (!mIsActive) return;
271
272         if (!startInFilmstrip) {
273             // Launch photos in lights out mode
274             mActivity.getGLRoot().setLightsOutMode(true);
275         }
276
277         MediaItem item = mAlbumDataAdapter.get(slotIndex);
278         if (item == null) return; // Item not ready yet, ignore the click
279         if (mGetContent) {
280             onGetContent(item);
281         } else if (mLaunchedFromPhotoPage) {
282             TransitionStore transitions = mActivity.getTransitionStore();
283             transitions.put(
284                     PhotoPage.KEY_ALBUMPAGE_TRANSITION,
285                     PhotoPage.MSG_ALBUMPAGE_PICKED);
286             transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex);
287             onBackPressed();
288         } else {
289             // Get into the PhotoPage.
290             // mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
291             Bundle data = new Bundle();
292             data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex);
293             data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT,
294                     mSlotView.getSlotRect(slotIndex, mRootPane));
295             data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
296                     mMediaSetPath.toString());
297             data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH,
298                     item.getPath().toString());
299             data.putInt(PhotoPage.KEY_ALBUMPAGE_TRANSITION,
300                     PhotoPage.MSG_ALBUMPAGE_STARTED);
301             data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP,
302                     startInFilmstrip);
303             data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, mMediaSet.isCameraRoll());
304             if (startInFilmstrip) {
305                 mActivity.getStateManager().switchState(this, PhotoPage.class, data);
306             } else {
307                 mActivity.getStateManager().startStateForResult(
308                             PhotoPage.class, REQUEST_PHOTO, data);
309             }
310         }
311     }
312
313     private void onGetContent(final MediaItem item) {
314         DataManager dm = mActivity.getDataManager();
315         Activity activity = mActivity;
316         if (mData.getString(Gallery.EXTRA_CROP) != null) {
317             // TODO: Handle MtpImagew
318             Uri uri = dm.getContentUri(item.getPath());
319             Intent intent = new Intent(CropImage.ACTION_CROP, uri)
320                     .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
321                     .putExtras(getData());
322             if (mData.getParcelable(MediaStore.EXTRA_OUTPUT) == null) {
323                 intent.putExtra(CropImage.KEY_RETURN_DATA, true);
324             }
325             activity.startActivity(intent);
326             activity.finish();
327         } else {
328             Intent intent = new Intent(null, item.getContentUri())
329                 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
330             activity.setResult(Activity.RESULT_OK, intent);
331             activity.finish();
332         }
333     }
334
335     public void onLongTap(int slotIndex) {
336         if (mGetContent) return;
337         MediaItem item = mAlbumDataAdapter.get(slotIndex);
338         if (item == null) return;
339         mSelectionManager.setAutoLeaveSelectionMode(true);
340         mSelectionManager.toggle(item.getPath());
341         mSlotView.invalidate();
342     }
343
344     @Override
345     public void doCluster(int clusterType) {
346         String basePath = mMediaSet.getPath().toString();
347         String newPath = FilterUtils.newClusterPath(basePath, clusterType);
348         Bundle data = new Bundle(getData());
349         data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath);
350         if (mShowClusterMenu) {
351             Context context = mActivity.getAndroidContext();
352             data.putString(AlbumSetPage.KEY_SET_TITLE, mMediaSet.getName());
353             data.putString(AlbumSetPage.KEY_SET_SUBTITLE,
354                     GalleryActionBar.getClusterByTypeString(context, clusterType));
355         }
356
357         // mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
358         mActivity.getStateManager().startStateForResult(
359                 AlbumSetPage.class, REQUEST_DO_ANIMATION, data);
360     }
361
362     @Override
363     protected void onCreate(Bundle data, Bundle restoreState) {
364         super.onCreate(data, restoreState);
365         mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER);
366         initializeViews();
367         initializeData(data);
368         mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false);
369         mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false);
370         mDetailsSource = new MyDetailsSource();
371         Context context = mActivity.getAndroidContext();
372         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
373
374         // Enable auto-select-all for mtp album
375         if (data.getBoolean(KEY_AUTO_SELECT_ALL)) {
376             mSelectionManager.selectAll();
377         }
378
379         mLaunchedFromPhotoPage =
380                 mActivity.getStateManager().hasStateClass(PhotoPage.class);
381         mInCameraApp = data.getBoolean(PhotoPage.KEY_APP_BRIDGE, false);
382
383         mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
384             @Override
385             public void handleMessage(Message message) {
386                 switch (message.what) {
387                     case MSG_PICK_PHOTO: {
388                         pickPhoto(message.arg1);
389                         break;
390                     }
391                     default:
392                         throw new AssertionError(message.what);
393                 }
394             }
395         };
396     }
397
398     @Override
399     protected void onResume() {
400         super.onResume();
401         mIsActive = true;
402
403         mResumeEffect = mActivity.getTransitionStore().get(KEY_RESUME_ANIMATION);
404         if (mResumeEffect != null) {
405             mAlbumView.setSlotFilter(mResumeEffect);
406             mResumeEffect.setPositionProvider(mPositionProvider);
407             mResumeEffect.start();
408         }
409
410         setContentPane(mRootPane);
411
412         boolean enableHomeButton = (mActivity.getStateManager().getStateCount() > 1) |
413                 mParentMediaSetString != null;
414         GalleryActionBar actionBar = mActivity.getGalleryActionBar();
415         actionBar.setDisplayOptions(enableHomeButton, false);
416         if (!mGetContent) {
417             actionBar.enableAlbumModeMenu(GalleryActionBar.ALBUM_GRID_MODE_SELECTED, this);
418         }
419
420         // Set the reload bit here to prevent it exit this page in clearLoadingBit().
421         setLoadingBit(BIT_LOADING_RELOAD);
422         mAlbumDataAdapter.resume();
423
424         mAlbumView.resume();
425         mAlbumView.setPressedIndex(-1);
426         mActionModeHandler.resume();
427         if (!mInitialSynced) {
428             setLoadingBit(BIT_LOADING_SYNC);
429             mSyncTask = mMediaSet.requestSync(this);
430         }
431         mInCameraAndWantQuitOnPause = mInCameraApp;
432     }
433
434     @Override
435     protected void onPause() {
436         super.onPause();
437         mIsActive = false;
438
439         if (mSelectionManager.inSelectionMode()) {
440             mSelectionManager.leaveSelectionMode();
441         }
442         mAlbumView.setSlotFilter(null);
443
444         mAlbumDataAdapter.pause();
445         mAlbumView.pause();
446         DetailsHelper.pause();
447         if (!mGetContent) {
448             mActivity.getGalleryActionBar().disableAlbumModeMenu(true);
449         }
450
451         if (mSyncTask != null) {
452             mSyncTask.cancel();
453             mSyncTask = null;
454             clearLoadingBit(BIT_LOADING_SYNC);
455         }
456         mActionModeHandler.pause();
457     }
458
459     @Override
460     protected void onDestroy() {
461         super.onDestroy();
462         if (mAlbumDataAdapter != null) {
463             mAlbumDataAdapter.setLoadingListener(null);
464         }
465     }
466
467     private void initializeViews() {
468         mSelectionManager = new SelectionManager(mActivity, false);
469         mSelectionManager.setSelectionListener(this);
470         Config.AlbumPage config = Config.AlbumPage.get(mActivity);
471         mSlotView = new SlotView(mActivity, config.slotViewSpec);
472         mAlbumView = new AlbumSlotRenderer(mActivity, mSlotView,
473                 mSelectionManager, config.placeholderColor);
474         mSlotView.setSlotRenderer(mAlbumView);
475         mRootPane.addComponent(mSlotView);
476         mSlotView.setListener(new SlotView.SimpleListener() {
477             @Override
478             public void onDown(int index) {
479                 AlbumPage.this.onDown(index);
480             }
481
482             @Override
483             public void onUp(boolean followedByLongPress) {
484                 AlbumPage.this.onUp(followedByLongPress);
485             }
486
487             @Override
488             public void onSingleTapUp(int slotIndex) {
489                 AlbumPage.this.onSingleTapUp(slotIndex);
490             }
491
492             @Override
493             public void onLongTap(int slotIndex) {
494                 AlbumPage.this.onLongTap(slotIndex);
495             }
496         });
497         mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager);
498         mActionModeHandler.setActionModeListener(new ActionModeListener() {
499             @Override
500             public boolean onActionItemClicked(MenuItem item) {
501                 return onItemSelected(item);
502             }
503         });
504     }
505
506     private void initializeData(Bundle data) {
507         mMediaSetPath = Path.fromString(data.getString(KEY_MEDIA_PATH));
508         mParentMediaSetString = data.getString(KEY_PARENT_MEDIA_PATH);
509         mMediaSet = mActivity.getDataManager().getMediaSet(mMediaSetPath);
510         if (mMediaSet == null) {
511             Utils.fail("MediaSet is null. Path = %s", mMediaSetPath);
512         }
513         mSelectionManager.setSourceMediaSet(mMediaSet);
514         mAlbumDataAdapter = new AlbumDataLoader(mActivity, mMediaSet);
515         mAlbumDataAdapter.setLoadingListener(new MyLoadingListener());
516         mAlbumView.setModel(mAlbumDataAdapter);
517     }
518
519     private void showDetails() {
520         mShowDetails = true;
521         if (mDetailsHelper == null) {
522             mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource);
523             mDetailsHelper.setCloseListener(new CloseListener() {
524                 @Override
525                 public void onClose() {
526                     hideDetails();
527                 }
528             });
529         }
530         mDetailsHelper.show();
531     }
532
533     private void hideDetails() {
534         mShowDetails = false;
535         mDetailsHelper.hide();
536         mAlbumView.setHighlightItemPath(null);
537         mSlotView.invalidate();
538     }
539
540     @Override
541     protected boolean onCreateActionBar(Menu menu) {
542         GalleryActionBar actionBar = mActivity.getGalleryActionBar();
543         MenuInflater inflator = getSupportMenuInflater();
544         if (mGetContent) {
545             inflator.inflate(R.menu.pickup, menu);
546             int typeBits = mData.getInt(Gallery.KEY_TYPE_BITS,
547                     DataManager.INCLUDE_IMAGE);
548             actionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits));
549         } else {
550             inflator.inflate(R.menu.album, menu);
551             actionBar.setTitle(mMediaSet.getName());
552
553             menu.findItem(R.id.action_slideshow)
554                     .setVisible(!(mMediaSet instanceof MtpDevice));
555
556             FilterUtils.setupMenuItems(actionBar, mMediaSetPath, true);
557
558             menu.findItem(R.id.action_group_by).setVisible(mShowClusterMenu);
559             menu.findItem(R.id.action_camera).setVisible(
560                     MediaSetUtils.isCameraSource(mMediaSetPath)
561                     && GalleryUtils.isCameraAvailable(mActivity));
562
563         }
564         actionBar.setSubtitle(null);
565         return true;
566     }
567
568     private void prepareAnimationBackToFilmstrip(int slotIndex) {
569         if (mAlbumDataAdapter == null || !mAlbumDataAdapter.isActive(slotIndex)) return;
570         MediaItem item = mAlbumDataAdapter.get(slotIndex);
571         if (item == null) return;
572         TransitionStore transitions = mActivity.getTransitionStore();
573         transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex);
574         transitions.put(PhotoPage.KEY_OPEN_ANIMATION_RECT,
575                 mSlotView.getSlotRect(slotIndex, mRootPane));
576     }
577
578     private void switchToFilmstrip() {
579         if (mAlbumDataAdapter.size() < 1) return;
580         int targetPhoto = mSlotView.getVisibleStart();
581         prepareAnimationBackToFilmstrip(targetPhoto);
582         if(mLaunchedFromPhotoPage) {
583             onBackPressed();
584         } else {
585             pickPhoto(targetPhoto, true);
586         }
587     }
588
589     @Override
590     protected boolean onItemSelected(MenuItem item) {
591         switch (item.getItemId()) {
592             case android.R.id.home: {
593                 onUpPressed();
594                 return true;
595             }
596             case R.id.action_cancel:
597                 mActivity.getStateManager().finishState(this);
598                 return true;
599             case R.id.action_select:
600                 mSelectionManager.setAutoLeaveSelectionMode(false);
601                 mSelectionManager.enterSelectionMode();
602                 return true;
603             case R.id.action_group_by: {
604                 mActivity.getGalleryActionBar().showClusterDialog(this);
605                 return true;
606             }
607             case R.id.action_slideshow: {
608                 mInCameraAndWantQuitOnPause = false;
609                 Bundle data = new Bundle();
610                 data.putString(SlideshowPage.KEY_SET_PATH,
611                         mMediaSetPath.toString());
612                 data.putBoolean(SlideshowPage.KEY_REPEAT, true);
613                 mActivity.getStateManager().startStateForResult(
614                         SlideshowPage.class, REQUEST_SLIDESHOW, data);
615                 return true;
616             }
617             case R.id.action_details: {
618                 if (mShowDetails) {
619                     hideDetails();
620                 } else {
621                     showDetails();
622                 }
623                 return true;
624             }
625             case R.id.action_camera: {
626                 GalleryUtils.startCameraActivity(mActivity);
627                 return true;
628             }
629             default:
630                 return false;
631         }
632     }
633
634     @Override
635     protected void onStateResult(int request, int result, Intent data) {
636         switch (request) {
637             case REQUEST_SLIDESHOW: {
638                 // data could be null, if there is no images in the album
639                 if (data == null) return;
640                 mFocusIndex = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0);
641                 mSlotView.setCenterIndex(mFocusIndex);
642                 break;
643             }
644             case REQUEST_PHOTO: {
645                 if (data == null) return;
646                 mFocusIndex = data.getIntExtra(PhotoPage.KEY_RETURN_INDEX_HINT, 0);
647                 mSlotView.makeSlotVisible(mFocusIndex);
648                 break;
649             }
650             case REQUEST_DO_ANIMATION: {
651                 mSlotView.startRisingAnimation();
652                 break;
653             }
654         }
655     }
656
657     @Override
658     public void onSelectionModeChange(int mode) {
659         switch (mode) {
660             case SelectionManager.ENTER_SELECTION_MODE: {
661                 mActionModeHandler.startActionMode();
662                 if (mHapticsEnabled) mVibrator.vibrate(100);
663                 break;
664             }
665             case SelectionManager.LEAVE_SELECTION_MODE: {
666                 mActionModeHandler.finishActionMode();
667                 mRootPane.invalidate();
668                 break;
669             }
670             case SelectionManager.SELECT_ALL_MODE: {
671                 mActionModeHandler.updateSupportedOperation();
672                 mRootPane.invalidate();
673                 break;
674             }
675         }
676     }
677
678     @Override
679     public void onSelectionChange(Path path, boolean selected) {
680         int count = mSelectionManager.getSelectedCount();
681         String format = mActivity.getResources().getQuantityString(
682                 R.plurals.number_of_items_selected, count);
683         mActionModeHandler.setTitle(String.format(format, count));
684         mActionModeHandler.updateSupportedOperation(path, selected);
685     }
686
687     @Override
688     public void onSyncDone(final MediaSet mediaSet, final int resultCode) {
689         Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result="
690                 + resultCode);
691         ((Activity) mActivity).runOnUiThread(new Runnable() {
692             @Override
693             public void run() {
694                 GLRoot root = mActivity.getGLRoot();
695                 root.lockRenderThread();
696                 try {
697                     if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) {
698                         mInitialSynced = true;
699                     }
700                     clearLoadingBit(BIT_LOADING_SYNC);
701                     if (resultCode == MediaSet.SYNC_RESULT_ERROR && mIsActive
702                             && (mAlbumDataAdapter.size() == 0)) {
703                         // show error toast only if the album is empty
704                         Toast.makeText(mActivity, R.string.sync_album_error,
705                                 Toast.LENGTH_LONG).show();
706                     }
707                 } finally {
708                     root.unlockRenderThread();
709                 }
710             }
711         });
712     }
713
714     private void setLoadingBit(int loadTaskBit) {
715         mLoadingBits |= loadTaskBit;
716     }
717
718     private void clearLoadingBit(int loadTaskBit) {
719         mLoadingBits &= ~loadTaskBit;
720         if (mLoadingBits == 0 && mIsActive) {
721             if (mAlbumDataAdapter.size() == 0) {
722                 Intent result = new Intent();
723                 result.putExtra(KEY_EMPTY_ALBUM, true);
724                 setStateResult(Activity.RESULT_OK, result);
725                 mActivity.getStateManager().finishState(this);
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() {
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 mAlbumDataAdapter.size();
748         }
749
750         @Override
751         public int setIndex() {
752             Path id = mSelectionManager.getSelected(false).get(0);
753             mIndex = mAlbumDataAdapter.findItem(id);
754             return mIndex;
755         }
756
757         @Override
758         public MediaDetails getDetails() {
759             // this relies on setIndex() being called beforehand
760             MediaObject item = mAlbumDataAdapter.get(mIndex);
761             if (item != null) {
762                 mAlbumView.setHighlightItemPath(item.getPath());
763                 return item.getDetails();
764             } else {
765                 return null;
766             }
767         }
768     }
769
770     @Override
771     public void onAlbumModeSelected(int mode) {
772         if (mode == GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED) {
773             switchToFilmstrip();
774         }
775     }
776 }