OSDN Git Service

am cceae7e7: (-s ours) Import revised translations. DO NOT MERGE
[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.app.ProgressDialog;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.net.Uri;
24 import android.os.Bundle;
25 import android.os.Vibrator;
26 import android.provider.MediaStore;
27 import android.view.ActionMode;
28 import android.view.Menu;
29 import android.view.MenuInflater;
30 import android.view.MenuItem;
31 import android.widget.Toast;
32
33 import com.android.gallery3d.R;
34 import com.android.gallery3d.common.Utils;
35 import com.android.gallery3d.data.DataManager;
36 import com.android.gallery3d.data.MediaDetails;
37 import com.android.gallery3d.data.MediaItem;
38 import com.android.gallery3d.data.MediaObject;
39 import com.android.gallery3d.data.MediaSet;
40 import com.android.gallery3d.data.MtpDevice;
41 import com.android.gallery3d.data.Path;
42 import com.android.gallery3d.ui.ActionModeHandler;
43 import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
44 import com.android.gallery3d.ui.AlbumView;
45 import com.android.gallery3d.ui.DetailsHelper;
46 import com.android.gallery3d.ui.DetailsHelper.CloseListener;
47 import com.android.gallery3d.ui.GLCanvas;
48 import com.android.gallery3d.ui.GLView;
49 import com.android.gallery3d.ui.GridDrawer;
50 import com.android.gallery3d.ui.HighlightDrawer;
51 import com.android.gallery3d.ui.PositionProvider;
52 import com.android.gallery3d.ui.PositionRepository;
53 import com.android.gallery3d.ui.PositionRepository.Position;
54 import com.android.gallery3d.ui.SelectionManager;
55 import com.android.gallery3d.ui.SlotView;
56 import com.android.gallery3d.ui.StaticBackground;
57 import com.android.gallery3d.util.Future;
58 import com.android.gallery3d.util.GalleryUtils;
59
60 import java.util.Random;
61
62 public class AlbumPage extends ActivityState implements GalleryActionBar.ClusterRunner,
63         SelectionManager.SelectionListener, MediaSet.SyncListener {
64     @SuppressWarnings("unused")
65     private static final String TAG = "AlbumPage";
66
67     public static final String KEY_MEDIA_PATH = "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
72     private static final int REQUEST_SLIDESHOW = 1;
73     private static final int REQUEST_PHOTO = 2;
74     private static final int REQUEST_DO_ANIMATION = 3;
75
76     private static final float USER_DISTANCE_METER = 0.3f;
77
78     private boolean mIsActive = false;
79     private StaticBackground mStaticBackground;
80     private AlbumView mAlbumView;
81     private Path mMediaSetPath;
82
83     private AlbumDataAdapter mAlbumDataAdapter;
84
85     protected SelectionManager mSelectionManager;
86     private Vibrator mVibrator;
87     private GridDrawer mGridDrawer;
88     private HighlightDrawer mHighlightDrawer;
89
90     private boolean mGetContent;
91     private boolean mShowClusterMenu;
92
93     private ActionMode mActionMode;
94     private ActionModeHandler mActionModeHandler;
95     private int mFocusIndex = 0;
96     private DetailsHelper mDetailsHelper;
97     private MyDetailsSource mDetailsSource;
98     private MediaSet mMediaSet;
99     private boolean mShowDetails;
100     private float mUserDistance; // in pixel
101
102     private ProgressDialog mProgressDialog;
103     private Future<?> mPendingTask;
104
105     private Future<Integer> mSyncTask = null;
106
107     private final GLView mRootPane = new GLView() {
108         private final float mMatrix[] = new float[16];
109
110         @Override
111         protected void onLayout(
112                 boolean changed, int left, int top, int right, int bottom) {
113             mStaticBackground.layout(0, 0, right - left, bottom - top);
114
115             int slotViewTop = GalleryActionBar.getHeight((Activity) mActivity);
116             int slotViewBottom = bottom - top;
117             int slotViewRight = right - left;
118
119             if (mShowDetails) {
120                 mDetailsHelper.layout(left, slotViewTop, right, bottom);
121             } else {
122                 mAlbumView.setSelectionDrawer(mGridDrawer);
123             }
124
125             mAlbumView.layout(0, slotViewTop, slotViewRight, slotViewBottom);
126             GalleryUtils.setViewPointMatrix(mMatrix,
127                     (right - left) / 2, (bottom - top) / 2, -mUserDistance);
128             PositionRepository.getInstance(mActivity).setOffset(
129                     0, slotViewTop);
130         }
131
132         @Override
133         protected void render(GLCanvas canvas) {
134             canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
135             canvas.multiplyMatrix(mMatrix, 0);
136             super.render(canvas);
137             canvas.restore();
138         }
139     };
140
141     @Override
142     protected void onBackPressed() {
143         if (mShowDetails) {
144             hideDetails();
145         } else if (mSelectionManager.inSelectionMode()) {
146             mSelectionManager.leaveSelectionMode();
147         } else {
148             mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
149             super.onBackPressed();
150         }
151     }
152
153     private void onDown(int index) {
154         MediaItem item = mAlbumDataAdapter.get(index);
155         Path path = (item == null) ? null : item.getPath();
156         mSelectionManager.setPressedPath(path);
157         mAlbumView.invalidate();
158     }
159
160     private void onUp() {
161         mSelectionManager.setPressedPath(null);
162         mAlbumView.invalidate();
163     }
164
165     public void onSingleTapUp(int slotIndex) {
166         MediaItem item = mAlbumDataAdapter.get(slotIndex);
167         if (item == null) {
168             Log.w(TAG, "item not ready yet, ignore the click");
169             return;
170         }
171         if (mShowDetails) {
172             mHighlightDrawer.setHighlightItem(item.getPath());
173             mDetailsHelper.reloadDetails(slotIndex);
174         } else if (!mSelectionManager.inSelectionMode()) {
175             if (mGetContent) {
176                 onGetContent(item);
177             } else {
178                 boolean playVideo =
179                     (item.getSupportedOperations() & MediaItem.SUPPORT_PLAY) != 0;
180                 if (playVideo) {
181                     // Play the video.
182                     PhotoPage.playVideo((Activity) mActivity, item.getPlayUri(), item.getName());
183                 } else {
184                     // Get into the PhotoPage.
185                     Bundle data = new Bundle();
186                     mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
187                     data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex);
188                     data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
189                             mMediaSetPath.toString());
190                     data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH,
191                             item.getPath().toString());
192                     mActivity.getStateManager().startStateForResult(
193                             PhotoPage.class, REQUEST_PHOTO, data);
194                 }
195             }
196         } else {
197             mSelectionManager.toggle(item.getPath());
198             mDetailsSource.findIndex(slotIndex);
199             mAlbumView.invalidate();
200         }
201     }
202
203     private void onGetContent(final MediaItem item) {
204         DataManager dm = mActivity.getDataManager();
205         Activity activity = (Activity) mActivity;
206         if (mData.getString(Gallery.EXTRA_CROP) != null) {
207             // TODO: Handle MtpImagew
208             Uri uri = dm.getContentUri(item.getPath());
209             Intent intent = new Intent(CropImage.ACTION_CROP, uri)
210                     .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
211                     .putExtras(getData());
212             if (mData.getParcelable(MediaStore.EXTRA_OUTPUT) == null) {
213                 intent.putExtra(CropImage.KEY_RETURN_DATA, true);
214             }
215             activity.startActivity(intent);
216             activity.finish();
217         } else {
218             activity.setResult(Activity.RESULT_OK,
219                     new Intent(null, item.getContentUri()));
220             activity.finish();
221         }
222     }
223
224     public void onLongTap(int slotIndex) {
225         if (mGetContent) return;
226         if (mShowDetails) {
227             onSingleTapUp(slotIndex);
228         } else {
229             MediaItem item = mAlbumDataAdapter.get(slotIndex);
230             if (item == null) return;
231             mSelectionManager.setAutoLeaveSelectionMode(true);
232             mSelectionManager.toggle(item.getPath());
233             mDetailsSource.findIndex(slotIndex);
234             mAlbumView.invalidate();
235         }
236     }
237
238     public void doCluster(int clusterType) {
239         String basePath = mMediaSet.getPath().toString();
240         String newPath = FilterUtils.newClusterPath(basePath, clusterType);
241         Bundle data = new Bundle(getData());
242         data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath);
243         if (mShowClusterMenu) {
244             Context context = mActivity.getAndroidContext();
245             data.putString(AlbumSetPage.KEY_SET_TITLE, mMediaSet.getName());
246             data.putString(AlbumSetPage.KEY_SET_SUBTITLE,
247                     GalleryActionBar.getClusterByTypeString(context, clusterType));
248         }
249
250         mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
251         mActivity.getStateManager().startStateForResult(
252                 AlbumSetPage.class, REQUEST_DO_ANIMATION, data);
253     }
254
255     public void doFilter(int filterType) {
256         String basePath = mMediaSet.getPath().toString();
257         String newPath = FilterUtils.switchFilterPath(basePath, filterType);
258         Bundle data = new Bundle(getData());
259         data.putString(AlbumPage.KEY_MEDIA_PATH, newPath);
260         mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
261         mActivity.getStateManager().switchState(this, AlbumPage.class, data);
262     }
263
264     public void onOperationComplete() {
265         mAlbumView.invalidate();
266         // TODO: enable animation
267     }
268
269     @Override
270     protected void onCreate(Bundle data, Bundle restoreState) {
271         mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER);
272         initializeViews();
273         initializeData(data);
274         mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false);
275         mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false);
276         mDetailsSource = new MyDetailsSource();
277         Context context = mActivity.getAndroidContext();
278         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
279
280         startTransition(data);
281
282         // Enable auto-select-all for mtp album
283         if (data.getBoolean(KEY_AUTO_SELECT_ALL)) {
284             mSelectionManager.selectAll();
285         }
286     }
287
288     private void startTransition() {
289         final PositionRepository repository =
290                 PositionRepository.getInstance(mActivity);
291         mAlbumView.startTransition(new PositionProvider() {
292             private final Position mTempPosition = new Position();
293             public Position getPosition(long identity, Position target) {
294                 Position p = repository.get(identity);
295                 if (p != null) return p;
296                 mTempPosition.set(target);
297                 mTempPosition.z = 128;
298                 return mTempPosition;
299             }
300         });
301     }
302
303     private void startTransition(Bundle data) {
304         final PositionRepository repository =
305                 PositionRepository.getInstance(mActivity);
306         final int[] center = data == null
307                 ? null
308                 : data.getIntArray(KEY_SET_CENTER);
309         final Random random = new Random();
310         mAlbumView.startTransition(new PositionProvider() {
311             private final Position mTempPosition = new Position();
312             public Position getPosition(long identity, Position target) {
313                 Position p = repository.get(identity);
314                 if (p != null) return p;
315                 if (center != null) {
316                     random.setSeed(identity);
317                     mTempPosition.set(center[0], center[1],
318                             0, random.nextInt(60) - 30, 0);
319                 } else {
320                     mTempPosition.set(target);
321                     mTempPosition.z = 128;
322                 }
323                 return mTempPosition;
324             }
325         });
326     }
327
328     @Override
329     protected void onResume() {
330         super.onResume();
331         mIsActive = true;
332         setContentPane(mRootPane);
333         mAlbumDataAdapter.resume();
334         mAlbumView.resume();
335         mActionModeHandler.resume();
336     }
337
338     @Override
339     protected void onPause() {
340         super.onPause();
341         mIsActive = false;
342         mAlbumDataAdapter.pause();
343         mAlbumView.pause();
344         DetailsHelper.pause();
345         Future<?> task = mPendingTask;
346         if (task != null) {
347             // cancel on going task
348             task.cancel();
349             task.waitDone();
350             if (mProgressDialog != null) {
351                 mProgressDialog.dismiss();
352                 mProgressDialog = null;
353             }
354         }
355         if (mSyncTask != null) {
356             mSyncTask.cancel();
357             mSyncTask = null;
358         }
359         mActionModeHandler.pause();
360     }
361
362     @Override
363     protected void onDestroy() {
364         super.onDestroy();
365         if (mAlbumDataAdapter != null) {
366             mAlbumDataAdapter.setLoadingListener(null);
367         }
368     }
369
370     private void initializeViews() {
371         mStaticBackground = new StaticBackground((Context) mActivity);
372         mRootPane.addComponent(mStaticBackground);
373
374         mSelectionManager = new SelectionManager(mActivity, false);
375         mSelectionManager.setSelectionListener(this);
376         mGridDrawer = new GridDrawer((Context) mActivity, mSelectionManager);
377         Config.AlbumPage config = Config.AlbumPage.get((Context) mActivity);
378         mAlbumView = new AlbumView(mActivity, config.slotViewSpec,
379                 0 /* don't cache thumbnail */);
380         mAlbumView.setSelectionDrawer(mGridDrawer);
381         mRootPane.addComponent(mAlbumView);
382         mAlbumView.setListener(new SlotView.SimpleListener() {
383             @Override
384             public void onDown(int index) {
385                 AlbumPage.this.onDown(index);
386             }
387
388             @Override
389             public void onUp() {
390                 AlbumPage.this.onUp();
391             }
392
393             @Override
394             public void onSingleTapUp(int slotIndex) {
395                 AlbumPage.this.onSingleTapUp(slotIndex);
396             }
397
398             @Override
399             public void onLongTap(int slotIndex) {
400                 AlbumPage.this.onLongTap(slotIndex);
401             }
402         });
403         mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager);
404         mActionModeHandler.setActionModeListener(new ActionModeListener() {
405             public boolean onActionItemClicked(MenuItem item) {
406                 return onItemSelected(item);
407             }
408         });
409         mStaticBackground.setImage(R.drawable.background,
410                 R.drawable.background_portrait);
411     }
412
413     private void initializeData(Bundle data) {
414         mMediaSetPath = Path.fromString(data.getString(KEY_MEDIA_PATH));
415         mMediaSet = mActivity.getDataManager().getMediaSet(mMediaSetPath);
416         Utils.assertTrue(mMediaSet != null,
417                 "MediaSet is null. Path = %s", mMediaSetPath);
418         mSelectionManager.setSourceMediaSet(mMediaSet);
419         mAlbumDataAdapter = new AlbumDataAdapter(mActivity, mMediaSet);
420         mAlbumDataAdapter.setLoadingListener(new MyLoadingListener());
421         mAlbumView.setModel(mAlbumDataAdapter);
422     }
423
424     private void showDetails() {
425         mShowDetails = true;
426         if (mDetailsHelper == null) {
427             mHighlightDrawer = new HighlightDrawer(mActivity.getAndroidContext(),
428                     mSelectionManager);
429             mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource);
430             mDetailsHelper.setCloseListener(new CloseListener() {
431                 public void onClose() {
432                     hideDetails();
433                 }
434             });
435         }
436         mAlbumView.setSelectionDrawer(mHighlightDrawer);
437         mDetailsHelper.show();
438     }
439
440     private void hideDetails() {
441         mShowDetails = false;
442         mDetailsHelper.hide();
443         mAlbumView.setSelectionDrawer(mGridDrawer);
444         mAlbumView.invalidate();
445     }
446
447     @Override
448     protected boolean onCreateActionBar(Menu menu) {
449         Activity activity = (Activity) mActivity;
450         GalleryActionBar actionBar = mActivity.getGalleryActionBar();
451         MenuInflater inflater = activity.getMenuInflater();
452
453         if (mGetContent) {
454             inflater.inflate(R.menu.pickup, menu);
455             int typeBits = mData.getInt(Gallery.KEY_TYPE_BITS,
456                     DataManager.INCLUDE_IMAGE);
457
458             actionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits));
459         } else {
460             inflater.inflate(R.menu.album, menu);
461             actionBar.setTitle(mMediaSet.getName());
462             if (mMediaSet instanceof MtpDevice) {
463                 menu.findItem(R.id.action_slideshow).setVisible(false);
464             } else {
465                 menu.findItem(R.id.action_slideshow).setVisible(true);
466             }
467
468             MenuItem groupBy = menu.findItem(R.id.action_group_by);
469             FilterUtils.setupMenuItems(actionBar, mMediaSetPath, true);
470
471             if (groupBy != null) {
472                 groupBy.setVisible(mShowClusterMenu);
473             }
474
475             actionBar.setTitle(mMediaSet.getName());
476         }
477         actionBar.setSubtitle(null);
478
479         return true;
480     }
481
482     @Override
483     protected boolean onItemSelected(MenuItem item) {
484         switch (item.getItemId()) {
485             case R.id.action_cancel:
486                 mActivity.getStateManager().finishState(this);
487                 return true;
488             case R.id.action_select:
489                 mSelectionManager.setAutoLeaveSelectionMode(false);
490                 mSelectionManager.enterSelectionMode();
491                 return true;
492             case R.id.action_group_by: {
493                 mActivity.getGalleryActionBar().showClusterDialog(this);
494                 return true;
495             }
496             case R.id.action_slideshow: {
497                 Bundle data = new Bundle();
498                 data.putString(SlideshowPage.KEY_SET_PATH,
499                         mMediaSetPath.toString());
500                 data.putBoolean(SlideshowPage.KEY_REPEAT, true);
501                 mActivity.getStateManager().startStateForResult(
502                         SlideshowPage.class, REQUEST_SLIDESHOW, data);
503                 return true;
504             }
505             case R.id.action_details: {
506                 if (mShowDetails) {
507                     hideDetails();
508                 } else {
509                     showDetails();
510                 }
511                 return true;
512             }
513             default:
514                 return false;
515         }
516     }
517
518     @Override
519     protected void onStateResult(int request, int result, Intent data) {
520         switch (request) {
521             case REQUEST_SLIDESHOW: {
522                 // data could be null, if there is no images in the album
523                 if (data == null) return;
524                 mFocusIndex = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0);
525                 mAlbumView.setCenterIndex(mFocusIndex);
526                 break;
527             }
528             case REQUEST_PHOTO: {
529                 if (data == null) return;
530                 mFocusIndex = data.getIntExtra(PhotoPage.KEY_INDEX_HINT, 0);
531                 mAlbumView.setCenterIndex(mFocusIndex);
532                 startTransition();
533                 break;
534             }
535             case REQUEST_DO_ANIMATION: {
536                 startTransition(null);
537                 break;
538             }
539         }
540     }
541
542     public void onSelectionModeChange(int mode) {
543         switch (mode) {
544             case SelectionManager.ENTER_SELECTION_MODE: {
545                 mActionMode = mActionModeHandler.startActionMode();
546                 mVibrator.vibrate(100);
547                 break;
548             }
549             case SelectionManager.LEAVE_SELECTION_MODE: {
550                 mActionMode.finish();
551                 mRootPane.invalidate();
552                 break;
553             }
554             case SelectionManager.SELECT_ALL_MODE: {
555                 mActionModeHandler.updateSupportedOperation();
556                 mRootPane.invalidate();
557                 break;
558             }
559         }
560     }
561
562     public void onSelectionChange(Path path, boolean selected) {
563         Utils.assertTrue(mActionMode != null);
564         int count = mSelectionManager.getSelectedCount();
565         String format = mActivity.getResources().getQuantityString(
566                 R.plurals.number_of_items_selected, count);
567         mActionModeHandler.setTitle(String.format(format, count));
568         mActionModeHandler.updateSupportedOperation(path, selected);
569     }
570
571     @Override
572     public void onSyncDone(final MediaSet mediaSet, final int resultCode) {
573         Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result="
574                 + resultCode);
575         ((Activity) mActivity).runOnUiThread(new Runnable() {
576             @Override
577             public void run() {
578                 if (!mIsActive) return;
579                 mediaSet.notifyContentChanged(); // force reload to handle spinner
580
581                 if (resultCode == MediaSet.SYNC_RESULT_ERROR) {
582                     Toast.makeText((Context) mActivity, R.string.sync_album_error,
583                             Toast.LENGTH_LONG).show();
584                 }
585             }
586         });
587     }
588
589     private class MyLoadingListener implements LoadingListener {
590         @Override
591         public void onLoadingStarted() {
592             GalleryUtils.setSpinnerVisibility((Activity) mActivity, true);
593         }
594
595         @Override
596         public void onLoadingFinished() {
597             if (!mIsActive) return;
598             if (mAlbumDataAdapter.size() == 0) {
599                 if (mSyncTask == null) {
600                     mSyncTask = mMediaSet.requestSync(AlbumPage.this);
601                 }
602                 if (mSyncTask.isDone()){
603                     Toast.makeText((Context) mActivity,
604                             R.string.empty_album, Toast.LENGTH_LONG).show();
605                     mActivity.getStateManager().finishState(AlbumPage.this);
606                 }
607             }
608             if (mSyncTask == null || mSyncTask.isDone()) {
609                 GalleryUtils.setSpinnerVisibility((Activity) mActivity, false);
610             }
611         }
612     }
613
614     private class MyDetailsSource implements DetailsHelper.DetailsSource {
615         private int mIndex;
616         public int size() {
617             return mAlbumDataAdapter.size();
618         }
619
620         public int getIndex() {
621             return mIndex;
622         }
623
624         // If requested index is out of active window, suggest a valid index.
625         // If there is no valid index available, return -1.
626         public int findIndex(int indexHint) {
627             if (mAlbumDataAdapter.isActive(indexHint)) {
628                 mIndex = indexHint;
629             } else {
630                 mIndex = mAlbumDataAdapter.getActiveStart();
631                 if (!mAlbumDataAdapter.isActive(mIndex)) {
632                     return -1;
633                 }
634             }
635             return mIndex;
636         }
637
638         public MediaDetails getDetails() {
639             MediaObject item = mAlbumDataAdapter.get(mIndex);
640             if (item != null) {
641                 mHighlightDrawer.setHighlightItem(item.getPath());
642                 return item.getDetails();
643             } else {
644                 return null;
645             }
646         }
647     }
648 }