AlbumSetPage.java revision d05b0be120bb217b4f56add24a4b31bee92455b2
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.Vibrator;
25import android.provider.MediaStore;
26import android.view.ActionMode;
27import android.view.Menu;
28import android.view.MenuInflater;
29import android.view.MenuItem;
30import android.widget.Toast;
31
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.AlbumSetView;
44import com.android.gallery3d.ui.DetailsHelper;
45import com.android.gallery3d.ui.DetailsHelper.CloseListener;
46import com.android.gallery3d.ui.GLCanvas;
47import com.android.gallery3d.ui.GLView;
48import com.android.gallery3d.ui.GridDrawer;
49import com.android.gallery3d.ui.HighlightDrawer;
50import com.android.gallery3d.ui.PositionProvider;
51import com.android.gallery3d.ui.PositionRepository;
52import com.android.gallery3d.ui.PositionRepository.Position;
53import com.android.gallery3d.ui.SelectionManager;
54import com.android.gallery3d.ui.SlotView;
55import com.android.gallery3d.ui.StaticBackground;
56import com.android.gallery3d.util.Future;
57import com.android.gallery3d.util.GalleryUtils;
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    public static final String KEY_MEDIA_PATH = "media-path";
66    public static final String KEY_SET_TITLE = "set-title";
67    public static final String KEY_SET_SUBTITLE = "set-subtitle";
68    public static final String KEY_SELECTED_CLUSTER_TYPE = "selected-cluster";
69
70    private static final int DATA_CACHE_SIZE = 256;
71    private static final int REQUEST_DO_ANIMATION = 1;
72
73    private static final int BIT_LOADING_RELOAD = 1;
74    private static final int BIT_LOADING_SYNC = 2;
75
76    private boolean mIsActive = false;
77    private StaticBackground mStaticBackground;
78    private AlbumSetView mAlbumSetView;
79
80    private MediaSet mMediaSet;
81    private String mTitle;
82    private String mSubtitle;
83    private boolean mShowClusterMenu;
84    private int mSelectedAction;
85    private Vibrator mVibrator;
86
87    protected SelectionManager mSelectionManager;
88    private AlbumSetDataAdapter mAlbumSetDataAdapter;
89    private GridDrawer mGridDrawer;
90    private HighlightDrawer mHighlightDrawer;
91
92    private boolean mGetContent;
93    private boolean mGetAlbum;
94    private ActionMode mActionMode;
95    private ActionModeHandler mActionModeHandler;
96    private DetailsHelper mDetailsHelper;
97    private MyDetailsSource mDetailsSource;
98    private boolean mShowDetails;
99    private EyePosition mEyePosition;
100
101    // The eyes' position of the user, the origin is at the center of the
102    // device and the unit is in pixels.
103    private float mX;
104    private float mY;
105    private float mZ;
106
107    private Future<Integer> mSyncTask = null;
108
109    private int mLoadingBits = 0;
110    private boolean mInitialSynced = false;
111
112    private final GLView mRootPane = new GLView() {
113        private final float mMatrix[] = new float[16];
114
115        @Override
116        protected void onLayout(
117                boolean changed, int left, int top, int right, int bottom) {
118            mStaticBackground.layout(0, 0, right - left, bottom - top);
119            mEyePosition.resetPosition();
120
121            int slotViewTop = GalleryActionBar.getHeight((Activity) mActivity);
122            int slotViewBottom = bottom - top;
123            int slotViewRight = right - left;
124
125            if (mShowDetails) {
126                mDetailsHelper.layout(left, slotViewTop, right, bottom);
127            } else {
128                mAlbumSetView.setSelectionDrawer(mGridDrawer);
129            }
130
131            mAlbumSetView.layout(0, slotViewTop, slotViewRight, slotViewBottom);
132            PositionRepository.getInstance(mActivity).setOffset(
133                    0, slotViewTop);
134        }
135
136        @Override
137        protected void render(GLCanvas canvas) {
138            canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
139            GalleryUtils.setViewPointMatrix(mMatrix,
140                    getWidth() / 2 + mX, getHeight() / 2 + mY, mZ);
141            canvas.multiplyMatrix(mMatrix, 0);
142            super.render(canvas);
143            canvas.restore();
144        }
145    };
146
147    @Override
148    public void onEyePositionChanged(float x, float y, float z) {
149        mRootPane.lockRendering();
150        mX = x;
151        mY = y;
152        mZ = z;
153        mRootPane.unlockRendering();
154        mRootPane.invalidate();
155    }
156
157    @Override
158    public void onBackPressed() {
159        if (mShowDetails) {
160            hideDetails();
161        } else if (mSelectionManager.inSelectionMode()) {
162            mSelectionManager.leaveSelectionMode();
163        } else {
164            mAlbumSetView.savePositions(
165                    PositionRepository.getInstance(mActivity));
166            super.onBackPressed();
167        }
168    }
169
170    private void savePositions(int slotIndex, int center[]) {
171        Rect offset = new Rect();
172        mRootPane.getBoundsOf(mAlbumSetView, offset);
173        mAlbumSetView.savePositions(PositionRepository.getInstance(mActivity));
174        Rect r = mAlbumSetView.getSlotRect(slotIndex);
175        int scrollX = mAlbumSetView.getScrollX();
176        int scrollY = mAlbumSetView.getScrollY();
177        center[0] = offset.left + (r.left + r.right) / 2 - scrollX;
178        center[1] = offset.top + (r.top + r.bottom) / 2 - scrollY;
179    }
180
181    public void onSingleTapUp(int slotIndex) {
182        MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex);
183        if (targetSet == null) return; // Content is dirty, we shall reload soon
184
185        if (mShowDetails) {
186            Path path = targetSet.getPath();
187            mHighlightDrawer.setHighlightItem(path);
188            mDetailsHelper.reloadDetails(slotIndex);
189        } else if (!mSelectionManager.inSelectionMode()) {
190            Bundle data = new Bundle(getData());
191            String mediaPath = targetSet.getPath().toString();
192            int[] center = new int[2];
193            savePositions(slotIndex, center);
194            data.putIntArray(AlbumPage.KEY_SET_CENTER, center);
195            if (mGetAlbum && targetSet.isLeafAlbum()) {
196                Activity activity = (Activity) mActivity;
197                Intent result = new Intent()
198                        .putExtra(AlbumPicker.KEY_ALBUM_PATH, targetSet.getPath().toString());
199                activity.setResult(Activity.RESULT_OK, result);
200                activity.finish();
201            } else if (targetSet.getSubMediaSetCount() > 0) {
202                data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath);
203                mActivity.getStateManager().startStateForResult(
204                        AlbumSetPage.class, REQUEST_DO_ANIMATION, data);
205            } else {
206                if (!mGetContent && (targetSet.getSupportedOperations()
207                        & MediaObject.SUPPORT_IMPORT) != 0) {
208                    data.putBoolean(AlbumPage.KEY_AUTO_SELECT_ALL, true);
209                }
210                data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath);
211                boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class);
212                // We only show cluster menu in the first AlbumPage in stack
213                data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum);
214                mActivity.getStateManager().startStateForResult(
215                        AlbumPage.class, REQUEST_DO_ANIMATION, data);
216            }
217        } else {
218            mSelectionManager.toggle(targetSet.getPath());
219            mAlbumSetView.invalidate();
220        }
221    }
222
223    private void onDown(int index) {
224        MediaSet set = mAlbumSetDataAdapter.getMediaSet(index);
225        Path path = (set == null) ? null : set.getPath();
226        mSelectionManager.setPressedPath(path);
227        mAlbumSetView.invalidate();
228    }
229
230    private void onUp() {
231        mSelectionManager.setPressedPath(null);
232        mAlbumSetView.invalidate();
233    }
234
235    public void onLongTap(int slotIndex) {
236        if (mGetContent || mGetAlbum) return;
237        if (mShowDetails) {
238            onSingleTapUp(slotIndex);
239        } else {
240            MediaSet set = mAlbumSetDataAdapter.getMediaSet(slotIndex);
241            if (set == null) return;
242            mSelectionManager.setAutoLeaveSelectionMode(true);
243            mSelectionManager.toggle(set.getPath());
244            mDetailsSource.findIndex(slotIndex);
245            mAlbumSetView.invalidate();
246        }
247    }
248
249    public void doCluster(int clusterType) {
250        String basePath = mMediaSet.getPath().toString();
251        String newPath = FilterUtils.switchClusterPath(basePath, clusterType);
252        Bundle data = new Bundle(getData());
253        data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath);
254        data.putInt(KEY_SELECTED_CLUSTER_TYPE, clusterType);
255        mAlbumSetView.savePositions(PositionRepository.getInstance(mActivity));
256        mActivity.getStateManager().switchState(this, AlbumSetPage.class, data);
257    }
258
259    public void doFilter(int filterType) {
260        String basePath = mMediaSet.getPath().toString();
261        String newPath = FilterUtils.switchFilterPath(basePath, filterType);
262        Bundle data = new Bundle(getData());
263        data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath);
264        mAlbumSetView.savePositions(PositionRepository.getInstance(mActivity));
265        mActivity.getStateManager().switchState(this, AlbumSetPage.class, data);
266    }
267
268    public void onOperationComplete() {
269        mAlbumSetView.invalidate();
270        // TODO: enable animation
271    }
272
273    @Override
274    public void onCreate(Bundle data, Bundle restoreState) {
275        initializeViews();
276        initializeData(data);
277        Context context = mActivity.getAndroidContext();
278        mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false);
279        mGetAlbum = data.getBoolean(Gallery.KEY_GET_ALBUM, false);
280        mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE);
281        mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE);
282        mEyePosition = new EyePosition(context, this);
283        mDetailsSource = new MyDetailsSource();
284        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
285        GalleryActionBar actionBar = mActivity.getGalleryActionBar();
286        if (actionBar != null) {
287            mSelectedAction = data.getInt(
288                    AlbumSetPage.KEY_SELECTED_CLUSTER_TYPE, FilterUtils.CLUSTER_BY_ALBUM);
289        }
290        startTransition();
291    }
292
293    private void clearLoadingBit(int loadingBit) {
294        mLoadingBits &= ~loadingBit;
295        if (mLoadingBits == 0 && mIsActive) {
296            GalleryUtils.setSpinnerVisibility((Activity) mActivity, false);
297
298            // Only show toast when there's no album and we are going to finish
299            // the page. Toast is redundant if we are going to stay on this page.
300            if ((mAlbumSetDataAdapter.size() == 0)) {
301                Toast.makeText((Context) mActivity,
302                        R.string.empty_album, Toast.LENGTH_LONG).show();
303                if (mActivity.getStateManager().getStateCount() > 1) {
304                    mActivity.getStateManager().finishState(this);
305                }
306            }
307        }
308    }
309
310    private void setLoadingBit(int loadingBit) {
311        if (mLoadingBits == 0 && mIsActive) {
312            GalleryUtils.setSpinnerVisibility((Activity) mActivity, true);
313        }
314        mLoadingBits |= loadingBit;
315    }
316
317    @Override
318    public void onPause() {
319        super.onPause();
320        mIsActive = false;
321        mActionModeHandler.pause();
322        mAlbumSetDataAdapter.pause();
323        mAlbumSetView.pause();
324        mEyePosition.pause();
325        DetailsHelper.pause();
326        GalleryActionBar actionBar = mActivity.getGalleryActionBar();
327        if (actionBar != null) actionBar.hideClusterMenu();
328        if (mSyncTask != null) {
329            mSyncTask.cancel();
330            mSyncTask = null;
331            clearLoadingBit(BIT_LOADING_SYNC);
332        }
333        GalleryUtils.setSpinnerVisibility((Activity) mActivity, false);
334    }
335
336    @Override
337    public void onResume() {
338        super.onResume();
339        mIsActive = true;
340        setContentPane(mRootPane);
341
342        // Set the reload bit here to prevent it exit this page in clearLoadingBit().
343        setLoadingBit(BIT_LOADING_RELOAD);
344        mAlbumSetDataAdapter.resume();
345
346        mAlbumSetView.resume();
347        mEyePosition.resume();
348        mActionModeHandler.resume();
349        GalleryActionBar actionBar = mActivity.getGalleryActionBar();
350        if (mShowClusterMenu && actionBar != null) {
351            actionBar.showClusterMenu(mSelectedAction, this);
352        }
353        if (!mInitialSynced) {
354            setLoadingBit(BIT_LOADING_SYNC);
355            mSyncTask = mMediaSet.requestSync(AlbumSetPage.this);
356        }
357    }
358
359    private void initializeData(Bundle data) {
360        String mediaPath = data.getString(AlbumSetPage.KEY_MEDIA_PATH);
361        mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath);
362        mSelectionManager.setSourceMediaSet(mMediaSet);
363        mAlbumSetDataAdapter = new AlbumSetDataAdapter(
364                mActivity, mMediaSet, DATA_CACHE_SIZE);
365        mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener());
366        mAlbumSetView.setModel(mAlbumSetDataAdapter);
367    }
368
369    private void initializeViews() {
370        mSelectionManager = new SelectionManager(mActivity, true);
371        mSelectionManager.setSelectionListener(this);
372        mStaticBackground = new StaticBackground(mActivity.getAndroidContext());
373        mRootPane.addComponent(mStaticBackground);
374
375        mGridDrawer = new GridDrawer((Context) mActivity, mSelectionManager);
376        Config.AlbumSetPage config = Config.AlbumSetPage.get((Context) mActivity);
377        mAlbumSetView = new AlbumSetView(mActivity, mGridDrawer,
378                config.slotViewSpec, config.labelSpec);
379        mAlbumSetView.setListener(new SlotView.SimpleListener() {
380            @Override
381            public void onDown(int index) {
382                AlbumSetPage.this.onDown(index);
383            }
384
385            @Override
386            public void onUp() {
387                AlbumSetPage.this.onUp();
388            }
389
390            @Override
391            public void onSingleTapUp(int slotIndex) {
392                AlbumSetPage.this.onSingleTapUp(slotIndex);
393            }
394
395            @Override
396            public void onLongTap(int slotIndex) {
397                AlbumSetPage.this.onLongTap(slotIndex);
398            }
399        });
400
401        mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager);
402        mActionModeHandler.setActionModeListener(new ActionModeListener() {
403            public boolean onActionItemClicked(MenuItem item) {
404                return onItemSelected(item);
405            }
406        });
407        mRootPane.addComponent(mAlbumSetView);
408
409        mStaticBackground.setImage(R.drawable.background,
410                R.drawable.background_portrait);
411    }
412
413    @Override
414    protected boolean onCreateActionBar(Menu menu) {
415        Activity activity = (Activity) mActivity;
416        GalleryActionBar actionBar = mActivity.getGalleryActionBar();
417        MenuInflater inflater = activity.getMenuInflater();
418
419        final boolean inAlbum = mActivity.getStateManager().hasStateClass(
420                AlbumPage.class);
421
422        if (mGetContent) {
423            inflater.inflate(R.menu.pickup, menu);
424            int typeBits = mData.getInt(
425                    Gallery.KEY_TYPE_BITS, DataManager.INCLUDE_IMAGE);
426            int id = R.string.select_image;
427            if ((typeBits & DataManager.INCLUDE_VIDEO) != 0) {
428                id = (typeBits & DataManager.INCLUDE_IMAGE) == 0
429                        ? R.string.select_video
430                        : R.string.select_item;
431            }
432            actionBar.setTitle(id);
433        } else  if (mGetAlbum) {
434            inflater.inflate(R.menu.pickup, menu);
435            actionBar.setTitle(R.string.select_album);
436        } else {
437            mShowClusterMenu = !inAlbum;
438            inflater.inflate(R.menu.albumset, menu);
439            MenuItem selectItem = menu.findItem(R.id.action_select);
440
441            if (selectItem != null) {
442                boolean selectAlbums = !inAlbum &&
443                        actionBar.getClusterTypeAction() == FilterUtils.CLUSTER_BY_ALBUM;
444                if (selectAlbums) {
445                    selectItem.setTitle(R.string.select_album);
446                } else {
447                    selectItem.setTitle(R.string.select_group);
448                }
449            }
450
451            FilterUtils.setupMenuItems(actionBar, mMediaSet.getPath(), false);
452            MenuItem switchCamera = menu.findItem(R.id.action_camera);
453            if (switchCamera != null) {
454                switchCamera.setVisible(GalleryUtils.isCameraAvailable(activity));
455            }
456
457            actionBar.setTitle(mTitle);
458            actionBar.setSubtitle(mSubtitle);
459        }
460        return true;
461    }
462
463    @Override
464    protected boolean onItemSelected(MenuItem item) {
465        Activity activity = (Activity) mActivity;
466        switch (item.getItemId()) {
467            case R.id.action_cancel:
468                activity.setResult(Activity.RESULT_CANCELED);
469                activity.finish();
470                return true;
471            case R.id.action_select:
472                mSelectionManager.setAutoLeaveSelectionMode(false);
473                mSelectionManager.enterSelectionMode();
474                return true;
475            case R.id.action_details:
476                if (mAlbumSetDataAdapter.size() != 0) {
477                    if (mShowDetails) {
478                        hideDetails();
479                    } else {
480                        showDetails();
481                    }
482                } else {
483                    Toast.makeText(activity,
484                            activity.getText(R.string.no_albums_alert),
485                            Toast.LENGTH_SHORT).show();
486                }
487                return true;
488            case R.id.action_camera: {
489                Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA)
490                        .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
491                        | Intent.FLAG_ACTIVITY_NEW_TASK);
492                activity.startActivity(intent);
493                return true;
494            }
495            case R.id.action_manage_offline: {
496                Bundle data = new Bundle();
497                String mediaPath = mActivity.getDataManager().getTopSetPath(
498                    DataManager.INCLUDE_ALL);
499                data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath);
500                mActivity.getStateManager().startState(ManageCachePage.class, data);
501                return true;
502            }
503            case R.id.action_sync_picasa_albums: {
504                PicasaSource.requestSync(activity);
505                return true;
506            }
507            case R.id.action_settings: {
508                activity.startActivity(new Intent(activity, GallerySettings.class));
509                return true;
510            }
511            default:
512                return false;
513        }
514    }
515
516    @Override
517    protected void onStateResult(int requestCode, int resultCode, Intent data) {
518        switch (requestCode) {
519            case REQUEST_DO_ANIMATION: {
520                startTransition();
521            }
522        }
523    }
524
525    private void startTransition() {
526        final PositionRepository repository =
527                PositionRepository.getInstance(mActivity);
528        mAlbumSetView.startTransition(new PositionProvider() {
529            private final Position mTempPosition = new Position();
530            public Position getPosition(long identity, Position target) {
531                Position p = repository.get(identity);
532                if (p == null) {
533                    p = mTempPosition;
534                    p.set(target.x, target.y, 128, target.theta, 1);
535                }
536                return p;
537            }
538        });
539    }
540
541    private String getSelectedString() {
542        GalleryActionBar actionBar = mActivity.getGalleryActionBar();
543        int count = mSelectionManager.getSelectedCount();
544        int action = actionBar.getClusterTypeAction();
545        int string = action == FilterUtils.CLUSTER_BY_ALBUM
546                ? R.plurals.number_of_albums_selected
547                : R.plurals.number_of_groups_selected;
548        String format = mActivity.getResources().getQuantityString(string, count);
549        return String.format(format, count);
550    }
551
552    public void onSelectionModeChange(int mode) {
553
554        switch (mode) {
555            case SelectionManager.ENTER_SELECTION_MODE: {
556                mActivity.getGalleryActionBar().hideClusterMenu();
557                mActionMode = mActionModeHandler.startActionMode();
558                mVibrator.vibrate(100);
559                break;
560            }
561            case SelectionManager.LEAVE_SELECTION_MODE: {
562                mActionMode.finish();
563                if (mShowClusterMenu) {
564                    mActivity.getGalleryActionBar().showClusterMenu(mSelectedAction, this);
565                }
566                mRootPane.invalidate();
567                break;
568            }
569            case SelectionManager.SELECT_ALL_MODE: {
570                mActionModeHandler.setTitle(getSelectedString());
571                mRootPane.invalidate();
572                break;
573            }
574        }
575    }
576
577    public void onSelectionChange(Path path, boolean selected) {
578        Utils.assertTrue(mActionMode != null);
579        mActionModeHandler.setTitle(getSelectedString());
580        mActionModeHandler.updateSupportedOperation(path, selected);
581    }
582
583    private void hideDetails() {
584        mShowDetails = false;
585        mDetailsHelper.hide();
586        mAlbumSetView.setSelectionDrawer(mGridDrawer);
587        mAlbumSetView.invalidate();
588    }
589
590    private void showDetails() {
591        mShowDetails = true;
592        if (mDetailsHelper == null) {
593            mHighlightDrawer = new HighlightDrawer(mActivity.getAndroidContext(),
594                    mSelectionManager);
595            mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource);
596            mDetailsHelper.setCloseListener(new CloseListener() {
597                public void onClose() {
598                    hideDetails();
599                }
600            });
601        }
602        mAlbumSetView.setSelectionDrawer(mHighlightDrawer);
603        mDetailsHelper.show();
604    }
605
606    @Override
607    public void onSyncDone(final MediaSet mediaSet, final int resultCode) {
608        if (resultCode == MediaSet.SYNC_RESULT_ERROR) {
609            Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result="
610                    + resultCode);
611        }
612        ((Activity) mActivity).runOnUiThread(new Runnable() {
613            @Override
614            public void run() {
615                if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) {
616                    mInitialSynced = true;
617                }
618                clearLoadingBit(BIT_LOADING_SYNC);
619                if (resultCode == MediaSet.SYNC_RESULT_ERROR && mIsActive) {
620                    Toast.makeText((Context) mActivity, R.string.sync_album_set_error,
621                            Toast.LENGTH_LONG).show();
622                }
623            }
624        });
625    }
626
627    private class MyLoadingListener implements LoadingListener {
628        public void onLoadingStarted() {
629            setLoadingBit(BIT_LOADING_RELOAD);
630        }
631
632        public void onLoadingFinished() {
633            clearLoadingBit(BIT_LOADING_RELOAD);
634        }
635    }
636
637    private class MyDetailsSource implements DetailsHelper.DetailsSource {
638        private int mIndex;
639        public int size() {
640            return mAlbumSetDataAdapter.size();
641        }
642
643        public int getIndex() {
644            return mIndex;
645        }
646
647        // If requested index is out of active window, suggest a valid index.
648        // If there is no valid index available, return -1.
649        public int findIndex(int indexHint) {
650            if (mAlbumSetDataAdapter.isActive(indexHint)) {
651                mIndex = indexHint;
652            } else {
653                mIndex = mAlbumSetDataAdapter.getActiveStart();
654                if (!mAlbumSetDataAdapter.isActive(mIndex)) {
655                    return -1;
656                }
657            }
658            return mIndex;
659        }
660
661        public MediaDetails getDetails() {
662            MediaObject item = mAlbumSetDataAdapter.getMediaSet(mIndex);
663            if (item != null) {
664                mHighlightDrawer.setHighlightItem(item.getPath());
665                return item.getDetails();
666            } else {
667                return null;
668            }
669        }
670    }
671}
672