summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/app/PhotoPage.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/app/PhotoPage.java')
-rw-r--r--src/com/android/gallery3d/app/PhotoPage.java581
1 files changed, 581 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
new file mode 100644
index 000000000..f28eb221d
--- /dev/null
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.app;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.data.DataManager;
+import com.android.gallery3d.data.MediaDetails;
+import com.android.gallery3d.data.MediaItem;
+import com.android.gallery3d.data.MediaObject;
+import com.android.gallery3d.data.MediaSet;
+import com.android.gallery3d.data.MtpDevice;
+import com.android.gallery3d.data.Path;
+import com.android.gallery3d.picasasource.PicasaSource;
+import com.android.gallery3d.ui.DetailsWindow;
+import com.android.gallery3d.ui.DetailsWindow.CloseListener;
+import com.android.gallery3d.ui.DetailsWindow.DetailsSource;
+import com.android.gallery3d.ui.FilmStripView;
+import com.android.gallery3d.ui.GLCanvas;
+import com.android.gallery3d.ui.GLView;
+import com.android.gallery3d.ui.ImportCompleteListener;
+import com.android.gallery3d.ui.MenuExecutor;
+import com.android.gallery3d.ui.PhotoView;
+import com.android.gallery3d.ui.PositionRepository;
+import com.android.gallery3d.ui.PositionRepository.Position;
+import com.android.gallery3d.ui.SelectionManager;
+import com.android.gallery3d.ui.SynchronizedHandler;
+import com.android.gallery3d.ui.UserInteractionListener;
+import com.android.gallery3d.util.GalleryUtils;
+
+import android.app.ActionBar;
+import android.app.ActionBar.OnMenuVisibilityListener;
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.WindowManager;
+import android.widget.ShareActionProvider;
+import android.widget.Toast;
+
+public class PhotoPage extends ActivityState
+ implements PhotoView.PhotoTapListener, FilmStripView.Listener,
+ UserInteractionListener {
+ private static final String TAG = "PhotoPage";
+
+ private static final int MSG_HIDE_BARS = 1;
+ private static final int HIDE_BARS_TIMEOUT = 3500;
+
+ private static final int REQUEST_SLIDESHOW = 1;
+ private static final int REQUEST_CROP = 2;
+ private static final int REQUEST_CROP_PICASA = 3;
+
+ public static final String KEY_MEDIA_SET_PATH = "media-set-path";
+ public static final String KEY_MEDIA_ITEM_PATH = "media-item-path";
+ public static final String KEY_INDEX_HINT = "index-hint";
+
+ private GalleryApp mApplication;
+ private SelectionManager mSelectionManager;
+
+ private PhotoView mPhotoView;
+ private PhotoPage.Model mModel;
+ private FilmStripView mFilmStripView;
+ private DetailsWindow mDetailsWindow;
+ private boolean mShowDetails;
+
+ // mMediaSet could be null if there is no KEY_MEDIA_SET_PATH supplied.
+ // E.g., viewing a photo in gmail attachment
+ private MediaSet mMediaSet;
+ private Menu mMenu;
+
+ private Intent mResultIntent = new Intent();
+ private int mCurrentIndex = 0;
+ private Handler mHandler;
+ private boolean mShowBars;
+ private ActionBar mActionBar;
+ private MyMenuVisibilityListener mMenuVisibilityListener;
+ private boolean mIsMenuVisible;
+ private boolean mIsInteracting;
+ private MediaItem mCurrentPhoto = null;
+ private MenuExecutor mMenuExecutor;
+ private boolean mIsActive;
+ private ShareActionProvider mShareActionProvider;
+
+ public static interface Model extends PhotoView.Model {
+ public void resume();
+ public void pause();
+ public boolean isEmpty();
+ public MediaItem getCurrentMediaItem();
+ public int getCurrentIndex();
+ public void setCurrentPhoto(Path path, int indexHint);
+ }
+
+ private class MyMenuVisibilityListener implements OnMenuVisibilityListener {
+ public void onMenuVisibilityChanged(boolean isVisible) {
+ mIsMenuVisible = isVisible;
+ refreshHidingMessage();
+ }
+ }
+
+ private GLView mRootPane = new GLView() {
+
+ @Override
+ protected void renderBackground(GLCanvas view) {
+ view.clearBuffer();
+ }
+
+ @Override
+ protected void onLayout(
+ boolean changed, int left, int top, int right, int bottom) {
+ mPhotoView.layout(0, 0, right - left, bottom - top);
+ PositionRepository.getInstance(mActivity).setOffset(0, 0);
+ int filmStripHeight = 0;
+ if (mFilmStripView != null) {
+ mFilmStripView.measure(
+ MeasureSpec.makeMeasureSpec(right - left, MeasureSpec.EXACTLY),
+ MeasureSpec.UNSPECIFIED);
+ filmStripHeight = mFilmStripView.getMeasuredHeight();
+ mFilmStripView.layout(0, bottom - top - filmStripHeight,
+ right - left, bottom - top);
+ }
+ if (mShowDetails) {
+ mDetailsWindow.measure(
+ MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ int width = mDetailsWindow.getMeasuredWidth();
+ int viewTop = GalleryActionBar.getHeight((Activity) mActivity);
+ mDetailsWindow.layout(
+ 0, viewTop, width, bottom - top - filmStripHeight);
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle data, Bundle restoreState) {
+ mActionBar = ((Activity) mActivity).getActionBar();
+ mSelectionManager = new SelectionManager(mActivity, false);
+ mMenuExecutor = new MenuExecutor(mActivity, mSelectionManager);
+
+ mPhotoView = new PhotoView(mActivity);
+ mPhotoView.setPhotoTapListener(this);
+ mRootPane.addComponent(mPhotoView);
+ mApplication = (GalleryApp)((Activity) mActivity).getApplication();
+
+ String setPathString = data.getString(KEY_MEDIA_SET_PATH);
+ Path itemPath = Path.fromString(data.getString(KEY_MEDIA_ITEM_PATH));
+
+ if (setPathString != null) {
+ mMediaSet = mActivity.getDataManager().getMediaSet(setPathString);
+ mCurrentIndex = data.getInt(KEY_INDEX_HINT, 0);
+ mMediaSet = (MediaSet)
+ mActivity.getDataManager().getMediaObject(setPathString);
+ if (mMediaSet == null) {
+ Log.w(TAG, "failed to restore " + setPathString);
+ }
+ PhotoDataAdapter pda = new PhotoDataAdapter(
+ mActivity, mPhotoView, mMediaSet, itemPath, mCurrentIndex);
+ mModel = pda;
+ mPhotoView.setModel(mModel);
+
+ Config.PhotoPage config = Config.PhotoPage.get((Context) mActivity);
+
+ mFilmStripView = new FilmStripView(mActivity, mMediaSet,
+ config.filmstripTopMargin, config.filmstripMidMargin, config.filmstripBottomMargin,
+ config.filmstripContentSize, config.filmstripThumbSize, config.filmstripBarSize,
+ config.filmstripGripSize, config.filmstripGripWidth);
+ mRootPane.addComponent(mFilmStripView);
+ mFilmStripView.setListener(this);
+ mFilmStripView.setUserInteractionListener(this);
+ mFilmStripView.setFocusIndex(mCurrentIndex);
+ mFilmStripView.setStartIndex(mCurrentIndex);
+
+ mResultIntent.putExtra(KEY_INDEX_HINT, mCurrentIndex);
+ setStateResult(Activity.RESULT_OK, mResultIntent);
+
+ pda.setDataListener(new PhotoDataAdapter.DataListener() {
+
+ public void onPhotoChanged(int index, Path item) {
+ mFilmStripView.setFocusIndex(index);
+ mCurrentIndex = index;
+ mResultIntent.putExtra(KEY_INDEX_HINT, index);
+ if (item != null) {
+ mResultIntent.putExtra(KEY_MEDIA_ITEM_PATH, item.toString());
+ MediaItem photo = mModel.getCurrentMediaItem();
+ if (photo != null) updateCurrentPhoto(photo);
+ } else {
+ mResultIntent.removeExtra(KEY_MEDIA_ITEM_PATH);
+ }
+ setStateResult(Activity.RESULT_OK, mResultIntent);
+ }
+
+ @Override
+ public void onLoadingFinished() {
+ GalleryUtils.setSpinnerVisibility((Activity) mActivity, false);
+ if (!mModel.isEmpty()) {
+ MediaItem photo = mModel.getCurrentMediaItem();
+ if (photo != null) updateCurrentPhoto(photo);
+ } else if (mIsActive) {
+ mActivity.getStateManager().finishState(PhotoPage.this);
+ }
+ }
+
+
+ @Override
+ public void onLoadingStarted() {
+ GalleryUtils.setSpinnerVisibility((Activity) mActivity, true);
+ }
+ });
+ } else {
+ // Get default media set by the URI
+ MediaItem mediaItem = (MediaItem)
+ mActivity.getDataManager().getMediaObject(itemPath);
+ mModel = new SinglePhotoDataAdapter(mActivity, mPhotoView, mediaItem);
+ mPhotoView.setModel(mModel);
+ updateCurrentPhoto(mediaItem);
+ }
+ mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_HIDE_BARS: {
+ hideBars();
+ break;
+ }
+ default: throw new AssertionError(message.what);
+ }
+ }
+ };
+
+ // start the opening animation
+ mPhotoView.setOpenedItem(itemPath);
+ }
+
+ private void updateCurrentPhoto(MediaItem photo) {
+ if (mCurrentPhoto == photo) return;
+ mCurrentPhoto = photo;
+ if (mCurrentPhoto == null) return;
+ updateMenuOperations();
+ if (mShowDetails) {
+ mDetailsWindow.reloadDetails(mModel.getCurrentIndex());
+ }
+ String title = photo.getName();
+ if (title != null) mActionBar.setTitle(title);
+ mPhotoView.showVideoPlayIcon(photo.getMediaType()
+ == MediaObject.MEDIA_TYPE_VIDEO);
+
+ // If we have an ActionBar then we update the share intent
+ if (mShareActionProvider != null) {
+ Path path = photo.getPath();
+ DataManager manager = mActivity.getDataManager();
+ int type = manager.getMediaType(path);
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType(MenuExecutor.getMimeType(type));
+ intent.putExtra(Intent.EXTRA_STREAM, manager.getContentUri(path));
+ mShareActionProvider.setShareIntent(intent);
+ }
+ }
+
+ private void updateMenuOperations() {
+ if (mCurrentPhoto == null || mMenu == null) return;
+ int supportedOperations = mCurrentPhoto.getSupportedOperations();
+ if (!GalleryUtils.isEditorAvailable((Context) mActivity, "image/*")) {
+ supportedOperations &= ~MediaObject.SUPPORT_EDIT;
+ }
+ MenuExecutor.updateMenuOperation(mMenu, supportedOperations);
+ }
+
+ private void showBars() {
+ if (mShowBars) return;
+ mShowBars = true;
+ mActionBar.show();
+ WindowManager.LayoutParams params = ((Activity) mActivity).getWindow().getAttributes();
+ params.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+ ((Activity) mActivity).getWindow().setAttributes(params);
+ if (mFilmStripView != null) {
+ mFilmStripView.show();
+ }
+ }
+
+ private void hideBars() {
+ if (!mShowBars) return;
+ mShowBars = false;
+ mActionBar.hide();
+ WindowManager.LayoutParams params = ((Activity) mActivity).getWindow().getAttributes();
+ params.systemUiVisibility = View. SYSTEM_UI_FLAG_LOW_PROFILE;
+ ((Activity) mActivity).getWindow().setAttributes(params);
+ if (mFilmStripView != null) {
+ mFilmStripView.hide();
+ }
+ }
+
+ private void refreshHidingMessage() {
+ mHandler.removeMessages(MSG_HIDE_BARS);
+ if (!mIsMenuVisible && !mIsInteracting) {
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_BARS, HIDE_BARS_TIMEOUT);
+ }
+ }
+
+ public void onUserInteraction() {
+ showBars();
+ refreshHidingMessage();
+ }
+
+ public void onUserInteractionTap() {
+ if (mShowBars) {
+ hideBars();
+ mHandler.removeMessages(MSG_HIDE_BARS);
+ } else {
+ showBars();
+ refreshHidingMessage();
+ }
+ }
+
+ public void onUserInteractionBegin() {
+ showBars();
+ mIsInteracting = true;
+ refreshHidingMessage();
+ }
+
+ public void onUserInteractionEnd() {
+ mIsInteracting = false;
+ refreshHidingMessage();
+ }
+
+ @Override
+ protected void onBackPressed() {
+ if (mShowDetails) {
+ hideDetails();
+ } else {
+ PositionRepository repository = PositionRepository.getInstance(mActivity);
+ repository.clear();
+ if (mCurrentPhoto != null) {
+ Position position = new Position();
+ position.x = mRootPane.getWidth() / 2;
+ position.y = mRootPane.getHeight() / 2;
+ position.z = -1000;
+ repository.putPosition(
+ Long.valueOf(System.identityHashCode(mCurrentPhoto.getPath())),
+ position);
+ }
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ protected boolean onCreateActionBar(Menu menu) {
+ MenuInflater inflater = ((Activity) mActivity).getMenuInflater();
+ inflater.inflate(R.menu.photo, menu);
+ menu.findItem(R.id.action_slideshow).setVisible(
+ mMediaSet != null && !(mMediaSet instanceof MtpDevice));
+ mShareActionProvider = GalleryActionBar.initializeShareActionProvider(menu);
+ mMenu = menu;
+ mShowBars = true;
+ updateMenuOperations();
+ return true;
+ }
+
+ @Override
+ protected boolean onItemSelected(MenuItem item) {
+ MediaItem current = mModel.getCurrentMediaItem();
+
+ if (current == null) {
+ // item is not ready, ignore
+ return true;
+ }
+
+ int currentIndex = mModel.getCurrentIndex();
+ Path path = current.getPath();
+
+ DataManager manager = mActivity.getDataManager();
+ int action = item.getItemId();
+ switch (action) {
+ case R.id.action_slideshow: {
+ Bundle data = new Bundle();
+ data.putString(SlideshowPage.KEY_SET_PATH,
+ mMediaSet.getPath().toString());
+ data.putInt(SlideshowPage.KEY_PHOTO_INDEX, currentIndex);
+ data.putBoolean(SlideshowPage.KEY_REPEAT, true);
+ mActivity.getStateManager().startStateForResult(
+ SlideshowPage.class, REQUEST_SLIDESHOW, data);
+ return true;
+ }
+ case R.id.action_crop: {
+ Activity activity = (Activity) mActivity;
+ Intent intent = new Intent(CropImage.CROP_ACTION);
+ intent.setClass(activity, CropImage.class);
+ intent.setData(manager.getContentUri(path));
+ activity.startActivityForResult(intent, PicasaSource.isPicasaImage(current)
+ ? REQUEST_CROP_PICASA
+ : REQUEST_CROP);
+ return true;
+ }
+ case R.id.action_details: {
+ if (mShowDetails) {
+ hideDetails();
+ } else {
+ showDetails(currentIndex);
+ }
+ return true;
+ }
+ case R.id.action_setas:
+ case R.id.action_confirm_delete:
+ case R.id.action_rotate_ccw:
+ case R.id.action_rotate_cw:
+ case R.id.action_show_on_map:
+ case R.id.action_edit:
+ mSelectionManager.deSelectAll();
+ mSelectionManager.toggle(path);
+ mMenuExecutor.onMenuClicked(item, null);
+ return true;
+ case R.id.action_import:
+ mSelectionManager.deSelectAll();
+ mSelectionManager.toggle(path);
+ mMenuExecutor.onMenuClicked(item,
+ new ImportCompleteListener(mActivity));
+ return true;
+ default :
+ return false;
+ }
+ }
+
+ private void hideDetails() {
+ mShowDetails = false;
+ mDetailsWindow.hide();
+ }
+
+ private void showDetails(int index) {
+ mShowDetails = true;
+ if (mDetailsWindow == null) {
+ mDetailsWindow = new DetailsWindow(mActivity, new MyDetailsSource());
+ mDetailsWindow.setCloseListener(new CloseListener() {
+ public void onClose() {
+ hideDetails();
+ }
+ });
+ mRootPane.addComponent(mDetailsWindow);
+ }
+ mDetailsWindow.reloadDetails(index);
+ mDetailsWindow.show();
+ }
+
+ public void onSingleTapUp(int x, int y) {
+ MediaItem item = mModel.getCurrentMediaItem();
+ if (item == null) {
+ // item is not ready, ignore
+ return;
+ }
+
+ boolean playVideo =
+ (item.getSupportedOperations() & MediaItem.SUPPORT_PLAY) != 0;
+
+ if (playVideo) {
+ // determine if the point is at center (1/6) of the photo view.
+ // (The position of the "play" icon is at center (1/6) of the photo)
+ int w = mPhotoView.getWidth();
+ int h = mPhotoView.getHeight();
+ playVideo = (Math.abs(x - w / 2) * 12 <= w)
+ && (Math.abs(y - h / 2) * 12 <= h);
+ }
+
+ if (playVideo) {
+ playVideo((Activity) mActivity, item.getPlayUri(), item.getName());
+ } else {
+ onUserInteractionTap();
+ }
+ }
+
+ public static void playVideo(Activity activity, Uri uri, String title) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW)
+ .setDataAndType(uri, "video/*");
+ intent.putExtra(Intent.EXTRA_TITLE, title);
+ activity.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(activity, activity.getString(R.string.video_err),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ // Called by FileStripView
+ public void onSlotSelected(int slotIndex) {
+ ((PhotoDataAdapter) mModel).jumpTo(slotIndex);
+ }
+
+ @Override
+ protected void onStateResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case REQUEST_CROP:
+ if (resultCode == Activity.RESULT_OK) {
+ if (data == null) break;
+ Path path = mApplication
+ .getDataManager().findPathByUri(data.getData());
+ if (path != null) {
+ mModel.setCurrentPhoto(path, mCurrentIndex);
+ }
+ }
+ break;
+ case REQUEST_CROP_PICASA: {
+ int message = resultCode == Activity.RESULT_OK
+ ? R.string.crop_saved
+ : R.string.crop_not_saved;
+ Toast.makeText(mActivity.getAndroidContext(),
+ message, Toast.LENGTH_SHORT).show();
+ break;
+ }
+ case REQUEST_SLIDESHOW: {
+ if (data == null) break;
+ String path = data.getStringExtra(SlideshowPage.KEY_ITEM_PATH);
+ int index = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0);
+ if (path != null) {
+ mModel.setCurrentPhoto(Path.fromString(path), index);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mIsActive = false;
+ if (mFilmStripView != null) {
+ mFilmStripView.pause();
+ }
+ if (mDetailsWindow != null) {
+ mDetailsWindow.pause();
+ }
+ mPhotoView.pause();
+ mModel.pause();
+ mHandler.removeMessages(MSG_HIDE_BARS);
+ mActionBar.removeOnMenuVisibilityListener(mMenuVisibilityListener);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mIsActive = true;
+ setContentPane(mRootPane);
+ mModel.resume();
+ mPhotoView.resume();
+ if (mFilmStripView != null) {
+ mFilmStripView.resume();
+ }
+ if (mMenuVisibilityListener == null) {
+ mMenuVisibilityListener = new MyMenuVisibilityListener();
+ }
+ mActionBar.addOnMenuVisibilityListener(mMenuVisibilityListener);
+ onUserInteraction();
+ }
+
+ private class MyDetailsSource implements DetailsSource {
+ public MediaDetails getDetails() {
+ return mModel.getCurrentMediaItem().getDetails();
+ }
+ public int size() {
+ return mMediaSet != null ? mMediaSet.getMediaItemCount() : 1;
+ }
+ public int findIndex(int indexHint) {
+ return indexHint;
+ }
+ }
+}