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