blob: 65c26278ac3a74426fc5641abe53f5d0f6483dc8 [file] [log] [blame]
/**
* 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 android.annotation.TargetApi;
import android.app.ActionBar.OnMenuVisibilityListener;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.drm.DrmHelper;
import android.graphics.Rect;
import android.media.MediaFile;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateBeamUrisCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.ShareActionProvider;
import android.widget.Toast;
import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.data.ComboAlbum;
import com.android.gallery3d.data.DataManager;
import com.android.gallery3d.data.FilterDeleteSet;
import com.android.gallery3d.data.FilterSource;
import com.android.gallery3d.data.LocalImage;
import com.android.gallery3d.data.MediaDetails;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.MediaObject;
import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback;
import com.android.gallery3d.data.MediaSet;
import com.android.gallery3d.data.Path;
import com.android.gallery3d.data.SecureAlbum;
import com.android.gallery3d.data.SecureSource;
import com.android.gallery3d.data.SnailAlbum;
import com.android.gallery3d.data.SnailItem;
import com.android.gallery3d.data.SnailSource;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.crop.CropActivity;
import com.android.gallery3d.picasasource.PicasaSource;
import com.android.gallery3d.ui.DetailsHelper;
import com.android.gallery3d.ui.DetailsHelper.CloseListener;
import com.android.gallery3d.ui.DetailsHelper.DetailsSource;
import com.android.gallery3d.ui.GLRootView;
import com.android.gallery3d.ui.GLView;
import com.android.gallery3d.ui.MenuExecutor;
import com.android.gallery3d.ui.PhotoView;
import com.android.gallery3d.ui.SelectionManager;
import com.android.gallery3d.ui.SynchronizedHandler;
import com.android.gallery3d.util.GalleryUtils;
import com.android.gallery3d.util.UsageStatistics;
import com.android.gallery3d.util.ViewGifImage;
import java.util.ArrayList;
import java.util.Locale;
public abstract class PhotoPage extends ActivityState implements
PhotoView.Listener, AppBridge.Server, ShareActionProvider.OnShareTargetSelectedListener,
PhotoPageBottomControls.Delegate, GalleryActionBar.OnAlbumModeSelectedListener {
private static final String TAG = "PhotoPage";
private static final int MSG_HIDE_BARS = 1;
private static final int MSG_ON_FULL_SCREEN_CHANGED = 4;
private static final int MSG_UPDATE_ACTION_BAR = 5;
private static final int MSG_UNFREEZE_GLROOT = 6;
private static final int MSG_WANT_BARS = 7;
private static final int MSG_REFRESH_BOTTOM_CONTROLS = 8;
private static final int MSG_ON_CAMERA_CENTER = 9;
private static final int MSG_ON_PICTURE_CENTER = 10;
private static final int MSG_REFRESH_IMAGE = 11;
private static final int MSG_UPDATE_PHOTO_UI = 12;
private static final int MSG_UPDATE_DEFERRED = 14;
private static final int MSG_UPDATE_SHARE_URI = 15;
private static final int MSG_UPDATE_PANORAMA_UI = 16;
private static final int HIDE_BARS_TIMEOUT = 3500;
private static final int UNFREEZE_GLROOT_TIMEOUT = 250;
private static final int REQUEST_SLIDESHOW = 1;
private static final int REQUEST_CROP = 2;
private static final int REQUEST_CROP_PICASA = 3;
private static final int REQUEST_EDIT = 4;
private static final int REQUEST_PLAY_VIDEO = 5;
private static final int REQUEST_TRIM = 6;
// Data cache size, equal to AlbumDataLoader.DATA_CACHE_SIZE
private static final int DATA_CACHE_SIZE = 256;
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";
public static final String KEY_OPEN_ANIMATION_RECT = "open-animation-rect";
public static final String KEY_APP_BRIDGE = "app-bridge";
public static final String KEY_TREAT_BACK_AS_UP = "treat-back-as-up";
public static final String KEY_START_IN_FILMSTRIP = "start-in-filmstrip";
public static final String KEY_RETURN_INDEX_HINT = "return-index-hint";
public static final String KEY_SHOW_WHEN_LOCKED = "show_when_locked";
public static final String KEY_IN_CAMERA_ROLL = "in_camera_roll";
public static final String KEY_READONLY = "read-only";
// Bundle key, used for checking whether it is from widget
public static final String KEY_IS_FROM_WIDGET = "is_from_widget";
public static final String KEY_ALBUMPAGE_TRANSITION = "albumpage-transition";
public static final int MSG_ALBUMPAGE_NONE = 0;
public static final int MSG_ALBUMPAGE_STARTED = 1;
public static final int MSG_ALBUMPAGE_RESUMED = 2;
public static final int MSG_ALBUMPAGE_PICKED = 4;
public static final String ACTION_NEXTGEN_EDIT = "action_nextgen_edit";
public static final String ACTION_SIMPLE_EDIT = "action_simple_edit";
private GalleryApp mApplication;
private SelectionManager mSelectionManager;
private PhotoView mPhotoView;
private PhotoPage.Model mModel;
private DetailsHelper mDetailsHelper;
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 FilterDeleteSet mMediaSet;
// The mediaset used by camera launched from secure lock screen.
private SecureAlbum mSecureAlbum;
private int mCurrentIndex = 0;
private Handler mHandler;
private boolean mShowBars = true;
private volatile boolean mActionBarAllowed = true;
private GalleryActionBar mActionBar;
private boolean mIsMenuVisible;
private boolean mHaveImageEditor;
private PhotoPageBottomControls mBottomControls;
private MediaItem mCurrentPhoto = null;
private MenuExecutor mMenuExecutor;
private boolean mIsActive;
private boolean mShowSpinner;
private String mSetPathString;
// This is the original mSetPathString before adding the camera preview item.
private boolean mReadOnlyView = false;
private String mOriginalSetPathString;
private AppBridge mAppBridge;
private SnailItem mScreenNailItem;
private SnailAlbum mScreenNailSet;
private OrientationManager mOrientationManager;
private boolean mTreatBackAsUp;
// Used for checking whether it is from widget
private boolean mIsFromWidget;
private boolean mStartInFilmstrip;
private boolean mHasCameraScreennailOrPlaceholder = false;
private boolean mRecenterCameraOnResume = true;
// These are only valid after the panorama callback
private boolean mIsPanorama;
private boolean mIsPanorama360;
private long mCameraSwitchCutoff = 0;
private boolean mSkipUpdateCurrentPhoto = false;
private static final long CAMERA_SWITCH_CUTOFF_THRESHOLD_MS = 300;
private static final long DEFERRED_UPDATE_MS = 250;
private boolean mDeferredUpdateWaiting = false;
private long mDeferUpdateUntil = Long.MAX_VALUE;
// The item that is deleted (but it can still be undeleted before commiting)
private Path mDeletePath;
private boolean mDeleteIsFocus; // whether the deleted item was in focus
private Uri[] mNfcPushUris = new Uri[1];
private final MyMenuVisibilityListener mMenuVisibilityListener =
new MyMenuVisibilityListener();
private int mLastSystemUiVis = 0;
private final PanoramaSupportCallback mUpdatePanoramaMenuItemsCallback = new PanoramaSupportCallback() {
@Override
public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama,
boolean isPanorama360) {
if (mediaObject == mCurrentPhoto) {
mHandler.obtainMessage(MSG_UPDATE_PANORAMA_UI, isPanorama360 ? 1 : 0, 0,
mediaObject).sendToTarget();
}
}
};
private final PanoramaSupportCallback mRefreshBottomControlsCallback = new PanoramaSupportCallback() {
@Override
public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama,
boolean isPanorama360) {
if (mediaObject == mCurrentPhoto) {
mHandler.obtainMessage(MSG_REFRESH_BOTTOM_CONTROLS, isPanorama ? 1 : 0, isPanorama360 ? 1 : 0,
mediaObject).sendToTarget();
}
}
};
private final PanoramaSupportCallback mUpdateShareURICallback = new PanoramaSupportCallback() {
@Override
public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama,
boolean isPanorama360) {
if (mediaObject == mCurrentPhoto) {
mHandler.obtainMessage(MSG_UPDATE_SHARE_URI, isPanorama360 ? 1 : 0, 0, mediaObject)
.sendToTarget();
}
}
};
public static interface Model extends PhotoView.Model {
public void resume();
public void pause();
public boolean isEmpty();
public void setCurrentPhoto(Path path, int indexHint);
}
private class MyMenuVisibilityListener implements OnMenuVisibilityListener {
@Override
public void onMenuVisibilityChanged(boolean isVisible) {
mIsMenuVisible = isVisible;
refreshHidingMessage();
}
}
@Override
protected int getBackgroundColorId() {
return R.color.photo_background;
}
private final GLView mRootPane = new GLView() {
@Override
protected void onLayout(
boolean changed, int left, int top, int right, int bottom) {
mPhotoView.layout(0, 0, right - left, bottom - top);
if (mShowDetails) {
mDetailsHelper.layout(left, mActionBar.getHeight(), right, bottom);
}
}
};
@Override
public void onCreate(Bundle data, Bundle restoreState) {
super.onCreate(data, restoreState);
mActionBar = mActivity.getGalleryActionBar();
mSelectionManager = new SelectionManager(mActivity, false);
mMenuExecutor = new MenuExecutor(mActivity, mSelectionManager);
mPhotoView = new PhotoView(mActivity);
mPhotoView.setListener(this);
mRootPane.addComponent(mPhotoView);
mApplication = (GalleryApp) ((Activity) mActivity).getApplication();
mOrientationManager = mActivity.getOrientationManager();
mActivity.getGLRoot().setOrientationSource(mOrientationManager);
mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_HIDE_BARS: {
hideBars();
break;
}
case MSG_REFRESH_BOTTOM_CONTROLS: {
if (mCurrentPhoto == message.obj && mBottomControls != null) {
mIsPanorama = message.arg1 == 1;
mIsPanorama360 = message.arg2 == 1;
mBottomControls.refresh();
}
break;
}
case MSG_ON_FULL_SCREEN_CHANGED: {
if (mAppBridge != null) {
mAppBridge.onFullScreenChanged(message.arg1 == 1);
}
break;
}
case MSG_UPDATE_ACTION_BAR: {
updateBars();
break;
}
case MSG_WANT_BARS: {
wantBars();
break;
}
case MSG_UNFREEZE_GLROOT: {
mActivity.getGLRoot().unfreeze();
break;
}
case MSG_UPDATE_DEFERRED: {
long nextUpdate = mDeferUpdateUntil - SystemClock.uptimeMillis();
if (nextUpdate <= 0) {
mDeferredUpdateWaiting = false;
updateUIForCurrentPhoto();
} else {
mHandler.sendEmptyMessageDelayed(MSG_UPDATE_DEFERRED, nextUpdate);
}
break;
}
case MSG_ON_CAMERA_CENTER: {
mSkipUpdateCurrentPhoto = false;
boolean stayedOnCamera = false;
if (!mPhotoView.getFilmMode()) {
stayedOnCamera = true;
} else if (SystemClock.uptimeMillis() < mCameraSwitchCutoff &&
mMediaSet.getMediaItemCount() > 1) {
mPhotoView.switchToImage(1);
} else {
if (mAppBridge != null) mPhotoView.setFilmMode(false);
stayedOnCamera = true;
}
if (stayedOnCamera) {
if (mAppBridge == null && mMediaSet.getTotalMediaItemCount() > 1) {
launchCamera();
/* We got here by swiping from photo 1 to the
placeholder, so make it be the thing that
is in focus when the user presses back from
the camera app */
mPhotoView.switchToImage(1);
} else {
updateBars();
updateCurrentPhoto(mModel.getMediaItem(0));
}
}
break;
}
case MSG_ON_PICTURE_CENTER: {
if (!mPhotoView.getFilmMode() && mCurrentPhoto != null
&& (mCurrentPhoto.getSupportedOperations() & MediaObject.SUPPORT_ACTION) != 0) {
mPhotoView.setFilmMode(true);
}
break;
}
case MSG_REFRESH_IMAGE: {
final MediaItem photo = mCurrentPhoto;
mCurrentPhoto = null;
updateCurrentPhoto(photo);
break;
}
case MSG_UPDATE_PHOTO_UI: {
updateUIForCurrentPhoto();
break;
}
case MSG_UPDATE_SHARE_URI: {
if (mCurrentPhoto == message.obj) {
boolean isPanorama360 = message.arg1 != 0;
Uri contentUri = mCurrentPhoto.getContentUri();
Intent panoramaIntent = null;
if (isPanorama360) {
panoramaIntent = createSharePanoramaIntent(contentUri);
}
Intent shareIntent = createShareIntent(mCurrentPhoto);
if (shareIntent != null) {
mActionBar.setShareIntents(panoramaIntent, shareIntent, PhotoPage.this);
}
setNfcBeamPushUri(contentUri);
}
break;
}
case MSG_UPDATE_PANORAMA_UI: {
if (mCurrentPhoto == message.obj) {
boolean isPanorama360 = message.arg1 != 0;
updatePanoramaUI(isPanorama360);
}
break;
}
default: throw new AssertionError(message.what);
}
}
};
mSetPathString = data.getString(KEY_MEDIA_SET_PATH);
mReadOnlyView = data.getBoolean(KEY_READONLY);
mOriginalSetPathString = mSetPathString;
setupNfcBeamPush();
String itemPathString = data.getString(KEY_MEDIA_ITEM_PATH);
Path itemPath = itemPathString != null ?
Path.fromString(data.getString(KEY_MEDIA_ITEM_PATH)) :
null;
mTreatBackAsUp = data.getBoolean(KEY_TREAT_BACK_AS_UP, false);
mIsFromWidget = data.getBoolean(KEY_IS_FROM_WIDGET, false);
mStartInFilmstrip = data.getBoolean(KEY_START_IN_FILMSTRIP, false);
boolean inCameraRoll = data.getBoolean(KEY_IN_CAMERA_ROLL, false);
mCurrentIndex = data.getInt(KEY_INDEX_HINT, 0);
if (mSetPathString != null) {
mShowSpinner = true;
mAppBridge = (AppBridge) data.getParcelable(KEY_APP_BRIDGE);
if (mAppBridge != null) {
mShowBars = false;
mHasCameraScreennailOrPlaceholder = true;
mAppBridge.setServer(this);
// Get the ScreenNail from AppBridge and register it.
int id = SnailSource.newId();
Path screenNailSetPath = SnailSource.getSetPath(id);
Path screenNailItemPath = SnailSource.getItemPath(id);
mScreenNailSet = (SnailAlbum) mActivity.getDataManager()
.getMediaObject(screenNailSetPath);
mScreenNailItem = (SnailItem) mActivity.getDataManager()
.getMediaObject(screenNailItemPath);
mScreenNailItem.setScreenNail(mAppBridge.attachScreenNail());
if (data.getBoolean(KEY_SHOW_WHEN_LOCKED, false)) {
// Set the flag to be on top of the lock screen.
mFlags |= FLAG_SHOW_WHEN_LOCKED;
}
// Don't display "empty album" action item for capture intents.
if (!mSetPathString.equals("/local/all/0")) {
// Check if the path is a secure album.
if (SecureSource.isSecurePath(mSetPathString)) {
mSecureAlbum = (SecureAlbum) mActivity.getDataManager()
.getMediaSet(mSetPathString);
mShowSpinner = false;
}
mSetPathString = "/filter/empty/{"+mSetPathString+"}";
}
// Combine the original MediaSet with the one for ScreenNail
// from AppBridge.
mSetPathString = "/combo/item/{" + screenNailSetPath +
"," + mSetPathString + "}";
// Start from the screen nail.
itemPath = screenNailItemPath;
} else if (inCameraRoll && GalleryUtils.isCameraAvailable(mActivity)) {
mSetPathString = "/combo/item/{" + FilterSource.FILTER_CAMERA_SHORTCUT +
"," + mSetPathString + "}";
mCurrentIndex++;
mHasCameraScreennailOrPlaceholder = true;
}
MediaSet originalSet = mActivity.getDataManager()
.getMediaSet(mSetPathString);
if (mHasCameraScreennailOrPlaceholder && originalSet instanceof ComboAlbum) {
// Use the name of the camera album rather than the default
// ComboAlbum behavior
((ComboAlbum) originalSet).useNameOfChild(1);
}
mSelectionManager.setSourceMediaSet(originalSet);
mSetPathString = "/filter/delete/{" + mSetPathString + "}";
mMediaSet = (FilterDeleteSet) mActivity.getDataManager()
.getMediaSet(mSetPathString);
if (mMediaSet == null) {
Log.w(TAG, "failed to restore " + mSetPathString);
}
if (itemPath == null) {
int mediaItemCount = mMediaSet.getMediaItemCount();
if (mediaItemCount > 0) {
if (mCurrentIndex >= mediaItemCount) mCurrentIndex = 0;
itemPath = mMediaSet.getMediaItem(mCurrentIndex, 1)
.get(0).getPath();
} else {
// Bail out, PhotoPage can't load on an empty album
return;
}
}
// If it is from widget, need to re-calcuate index and range
if (View.LAYOUT_DIRECTION_RTL == TextUtils
.getLayoutDirectionFromLocale(Locale.getDefault())
&& mIsFromWidget) {
int nMediaItemCount = mMediaSet.getMediaItemCount();
ArrayList<MediaItem> mediaItemList = mMediaSet.getMediaItem(0, nMediaItemCount);
int nItemIndex;
for (nItemIndex = 0; nItemIndex < nMediaItemCount; nItemIndex++) {
if (mediaItemList.get(nItemIndex).getPath().toString()
.equals(itemPath.toString())) {
int nIndex;
if (nItemIndex > DATA_CACHE_SIZE / 2
&& nItemIndex < (mMediaSet.getMediaItemCount() -
DATA_CACHE_SIZE / 2)) {
nIndex = mMediaSet.getMediaItemCount() - nItemIndex - 2;
} else {
nIndex = mMediaSet.getMediaItemCount() - nItemIndex - 1;
}
itemPath = mMediaSet.getMediaItem(nIndex, 1).get(0).getPath();
break;
}
}
}
PhotoDataAdapter pda = new PhotoDataAdapter(
mActivity, mPhotoView, mMediaSet, itemPath, mCurrentIndex,
mAppBridge == null ? -1 : 0,
mAppBridge == null ? false : mAppBridge.isPanorama(),
mAppBridge == null ? false : mAppBridge.isStaticCamera());
mModel = pda;
mPhotoView.setModel(mModel);
// If RTL and from widget, set the flag into PhotoDataAdapter.
if (View.LAYOUT_DIRECTION_RTL == TextUtils
.getLayoutDirectionFromLocale(Locale.getDefault())
&& mIsFromWidget) {
pda.setFromWidget(mIsFromWidget);
}
pda.setDataListener(new PhotoDataAdapter.DataListener() {
@Override
public void onPhotoChanged(int index, Path item) {
int oldIndex = mCurrentIndex;
mCurrentIndex = index;
if (mHasCameraScreennailOrPlaceholder) {
if (mCurrentIndex > 0) {
mSkipUpdateCurrentPhoto = false;
}
if (oldIndex == 0 && mCurrentIndex > 0
&& !mPhotoView.getFilmMode()) {
mPhotoView.setFilmMode(true);
if (mAppBridge != null) {
UsageStatistics.onEvent("CameraToFilmstrip",
UsageStatistics.TRANSITION_SWIPE, null);
}
} else if (oldIndex == 2 && mCurrentIndex == 1) {
mCameraSwitchCutoff = SystemClock.uptimeMillis() +
CAMERA_SWITCH_CUTOFF_THRESHOLD_MS;
mPhotoView.stopScrolling();
} else if (oldIndex >= 1 && mCurrentIndex == 0) {
mPhotoView.setWantPictureCenterCallbacks(true);
mSkipUpdateCurrentPhoto = true;
}
}
if (!mSkipUpdateCurrentPhoto) {
if (item != null) {
MediaItem photo = mModel.getMediaItem(0);
if (photo != null) updateCurrentPhoto(photo);
}
updateBars();
}
// Reset the timeout for the bars after a swipe
refreshHidingMessage();
}
@Override
public void onLoadingFinished(boolean loadingFailed) {
if (!mModel.isEmpty()) {
MediaItem photo = mModel.getMediaItem(0);
if (photo != null) updateCurrentPhoto(photo);
} else if (mIsActive) {
// We only want to finish the PhotoPage if there is no
// deletion that the user can undo.
if (mMediaSet.getNumberOfDeletions() == 0) {
mActivity.getStateManager().finishState(
PhotoPage.this);
}
}
}
@Override
public void onLoadingStarted() {
}
});
} 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);
mShowSpinner = false;
}
mPhotoView.setFilmMode(mStartInFilmstrip && mMediaSet.getMediaItemCount() > 1);
RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity)
.findViewById(mAppBridge != null ? R.id.content : R.id.gallery_root);
if (galleryRoot != null) {
if (mSecureAlbum == null) {
mBottomControls = new PhotoPageBottomControls(this, mActivity, galleryRoot);
}
}
((GLRootView) mActivity.getGLRoot()).setOnSystemUiVisibilityChangeListener(
new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
int diff = mLastSystemUiVis ^ visibility;
mLastSystemUiVis = visibility;
if ((diff & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
&& (visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
showBars();
}
}
});
}
@Override
public void onPictureCenter(boolean isCamera) {
isCamera = isCamera || (mHasCameraScreennailOrPlaceholder && mAppBridge == null);
mPhotoView.setWantPictureCenterCallbacks(false);
mHandler.removeMessages(MSG_ON_CAMERA_CENTER);
mHandler.removeMessages(MSG_ON_PICTURE_CENTER);
mHandler.sendEmptyMessage(isCamera ? MSG_ON_CAMERA_CENTER : MSG_ON_PICTURE_CENTER);
}
@Override
public boolean canDisplayBottomControls() {
return mIsActive && !mPhotoView.canUndo();
}
@Override
public boolean canDisplayBottomControl(int control) {
if (mCurrentPhoto == null) {
return false;
}
switch(control) {
case R.id.photopage_bottom_control_edit:
return mHaveImageEditor && mShowBars && !mReadOnlyView
&& !mPhotoView.getFilmMode()
&& (mCurrentPhoto.getSupportedOperations() & MediaItem.SUPPORT_EDIT) != 0
&& mCurrentPhoto.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE;
case R.id.photopage_bottom_control_panorama:
return mIsPanorama;
case R.id.photopage_bottom_control_tiny_planet:
return mHaveImageEditor && mShowBars
&& mIsPanorama360 && !mPhotoView.getFilmMode();
default:
return false;
}
}
@Override
public void onBottomControlClicked(int control) {
switch(control) {
case R.id.photopage_bottom_control_edit:
launchPhotoEditor();
return;
case R.id.photopage_bottom_control_panorama:
mActivity.getPanoramaViewHelper()
.showPanorama(mCurrentPhoto.getContentUri());
return;
case R.id.photopage_bottom_control_tiny_planet:
launchTinyPlanet();
return;
default:
return;
}
}
@TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
private void setupNfcBeamPush() {
if (!ApiHelper.HAS_SET_BEAM_PUSH_URIS) return;
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mActivity);
if (adapter != null) {
adapter.setBeamPushUris(null, mActivity);
adapter.setBeamPushUrisCallback(new CreateBeamUrisCallback() {
@Override
public Uri[] createBeamUris(NfcEvent event) {
return mNfcPushUris;
}
}, mActivity);
}
}
private void setNfcBeamPushUri(Uri uri) {
mNfcPushUris[0] = uri;
}
private Intent createShareIntent(MediaObject mediaObject) {
int type = mediaObject.getMediaType();
return new Intent(Intent.ACTION_SEND)
.setType(MenuExecutor.getMimeType(type))
.putExtra(Intent.EXTRA_STREAM, mediaObject.getContentUri())
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
private static Intent createSharePanoramaIntent(Uri contentUri) {
return new Intent(Intent.ACTION_SEND)
.setType(GalleryUtils.MIME_TYPE_PANORAMA360)
.putExtra(Intent.EXTRA_STREAM, contentUri)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
private void overrideTransitionToEditor() {
((Activity) mActivity).overridePendingTransition(android.R.anim.fade_in,
android.R.anim.fade_out);
}
private void launchTinyPlanet() {
// Deep link into tiny planet
MediaItem current = mModel.getMediaItem(0);
Intent intent = new Intent(FilterShowActivity.TINY_PLANET_ACTION);
intent.setClass(mActivity, FilterShowActivity.class);
intent.setDataAndType(current.getContentUri(), current.getMimeType())
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(FilterShowActivity.LAUNCH_FULLSCREEN,
mActivity.isFullscreen());
mActivity.startActivityForResult(intent, REQUEST_EDIT);
overrideTransitionToEditor();
}
private void launchCamera() {
mRecenterCameraOnResume = false;
GalleryUtils.startCameraActivity(mActivity);
}
private void launchPhotoEditor() {
MediaItem current = mModel.getMediaItem(0);
if (current == null || (current.getSupportedOperations()
& MediaObject.SUPPORT_EDIT) == 0) {
return;
}
Intent intent = new Intent(ACTION_NEXTGEN_EDIT);
intent.setDataAndType(current.getContentUri(), current.getMimeType())
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (mActivity.getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() == 0) {
intent.setAction(Intent.ACTION_EDIT);
}
intent.putExtra(FilterShowActivity.LAUNCH_FULLSCREEN,
mActivity.isFullscreen());
((Activity) mActivity).startActivityForResult(Intent.createChooser(intent, null),
REQUEST_EDIT);
overrideTransitionToEditor();
}
private void launchSimpleEditor() {
MediaItem current = mModel.getMediaItem(0);
if (current == null || (current.getSupportedOperations()
& MediaObject.SUPPORT_EDIT) == 0) {
return;
}
Intent intent = new Intent(ACTION_SIMPLE_EDIT);
intent.setDataAndType(current.getContentUri(), current.getMimeType())
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (mActivity.getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() == 0) {
intent.setAction(Intent.ACTION_EDIT);
}
intent.putExtra(FilterShowActivity.LAUNCH_FULLSCREEN,
mActivity.isFullscreen());
((Activity) mActivity).startActivityForResult(Intent.createChooser(intent, null),
REQUEST_EDIT);
overrideTransitionToEditor();
}
private void requestDeferredUpdate() {
mDeferUpdateUntil = SystemClock.uptimeMillis() + DEFERRED_UPDATE_MS;
if (!mDeferredUpdateWaiting) {
mDeferredUpdateWaiting = true;
mHandler.sendEmptyMessageDelayed(MSG_UPDATE_DEFERRED, DEFERRED_UPDATE_MS);
}
}
private void updateUIForCurrentPhoto() {
if (mCurrentPhoto == null) return;
// If by swiping or deletion the user ends up on an action item
// and zoomed in, zoom out so that the context of the action is
// more clear
if ((mCurrentPhoto.getSupportedOperations() & MediaObject.SUPPORT_ACTION) != 0
&& !mPhotoView.getFilmMode()) {
mPhotoView.setWantPictureCenterCallbacks(true);
}
updateMenuOperations();
refreshBottomControlsWhenReady();
if (mShowDetails) {
mDetailsHelper.reloadDetails();
}
if ((mSecureAlbum == null)
&& (mCurrentPhoto.getSupportedOperations() & MediaItem.SUPPORT_SHARE) != 0) {
mCurrentPhoto.getPanoramaSupport(mUpdateShareURICallback);
}
}
private void updateCurrentPhoto(MediaItem photo) {
if (mCurrentPhoto == photo) return;
mCurrentPhoto = photo;
if (mPhotoView.getFilmMode()) {
requestDeferredUpdate();
} else {
updateUIForCurrentPhoto();
// Manage DRM rights while image selection changed. this
// flow will comes for both image and video, but here
// we will consume rights for image files only.
// Do not consume rights of a GIF image and video here.
// ViewGifImage will take care of GIF rights consumption stub.
// MediaPlayer will handle the video rights consumption stub.
String mime = mCurrentPhoto.getMimeType();
if (!TextUtils.isEmpty(mime) && !mime.equals("image/gif")
&& !mime.startsWith("video/")) {
DrmHelper.manageDrmLicense(mActivity.getAndroidContext(),
mHandler, mCurrentPhoto.getFilePath(),
mCurrentPhoto.getMimeType());
}
}
}
private void updateMenuOperations() {
Menu menu = mActionBar.getMenu();
// it could be null if onCreateActionBar has not been called yet
if (menu == null) return;
MenuItem item = menu.findItem(R.id.action_slideshow);
if (item != null) {
item.setVisible((mSecureAlbum == null) && canDoSlideShow());
}
if (mCurrentPhoto == null) return;
int supportedOperations = mCurrentPhoto.getSupportedOperations();
if (mReadOnlyView) {
supportedOperations &= ~MediaObject.SUPPORT_EDIT;
}
if (mSecureAlbum != null) {
supportedOperations &= MediaObject.SUPPORT_DELETE;
} else {
mCurrentPhoto.getPanoramaSupport(mUpdatePanoramaMenuItemsCallback);
if (!mHaveImageEditor) {
supportedOperations &= ~MediaObject.SUPPORT_EDIT;
}
}
MenuExecutor.updateMenuOperation(menu, supportedOperations);
}
private boolean canDoSlideShow() {
if (mMediaSet == null || mCurrentPhoto == null) {
return false;
}
if (mCurrentPhoto.getMediaType() != MediaObject.MEDIA_TYPE_IMAGE) {
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// Action Bar show/hide management
//////////////////////////////////////////////////////////////////////////
private void showBars() {
if (mShowBars) return;
mShowBars = true;
mOrientationManager.unlockOrientation();
mActionBar.show();
mActivity.getGLRoot().setLightsOutMode(false);
refreshHidingMessage();
refreshBottomControlsWhenReady();
}
private void hideBars() {
if (!mShowBars) return;
mShowBars = false;
mActionBar.hide();
mActivity.getGLRoot().setLightsOutMode(true);
mHandler.removeMessages(MSG_HIDE_BARS);
refreshBottomControlsWhenReady();
}
private void refreshHidingMessage() {
mHandler.removeMessages(MSG_HIDE_BARS);
if (!mIsMenuVisible && !mPhotoView.getFilmMode()) {
mHandler.sendEmptyMessageDelayed(MSG_HIDE_BARS, HIDE_BARS_TIMEOUT);
}
}
private boolean canShowBars() {
// No bars if we are showing camera preview.
if (mAppBridge != null && mCurrentIndex == 0
&& !mPhotoView.getFilmMode()) return false;
// No bars if it's not allowed.
if (!mActionBarAllowed) return false;
Configuration config = mActivity.getResources().getConfiguration();
if (config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH) {
return false;
}
return true;
}
private void wantBars() {
if (canShowBars()) showBars();
}
private void toggleBars() {
if (mShowBars) {
hideBars();
} else {
if (canShowBars()) showBars();
}
}
private void updateBars() {
if (!canShowBars()) {
hideBars();
}
}
@Override
protected void onBackPressed() {
showBars();
if (mShowDetails) {
hideDetails();
} else if (mAppBridge == null || !switchWithCaptureAnimation(-1)) {
// We are leaving this page. Set the result now.
setResult();
if (mStartInFilmstrip && !mPhotoView.getFilmMode()) {
mPhotoView.setFilmMode(true);
} else if (mTreatBackAsUp) {
onUpPressed();
} else {
super.onBackPressed();
}
}
}
private void onUpPressed() {
if ((mStartInFilmstrip || mAppBridge != null)
&& !mPhotoView.getFilmMode()) {
mPhotoView.setFilmMode(true);
return;
}
if (mActivity.getStateManager().getStateCount() > 1) {
setResult();
super.onBackPressed();
return;
}
if (mOriginalSetPathString == null) return;
if (mAppBridge == null) {
// We're in view mode so set up the stacks on our own.
Bundle data = new Bundle(getData());
data.putString(AlbumPage.KEY_MEDIA_PATH, mOriginalSetPathString);
data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH,
mActivity.getDataManager().getTopSetPath(
DataManager.INCLUDE_ALL));
mActivity.getStateManager().switchState(this, AlbumPage.class, data);
} else {
GalleryUtils.startGalleryActivity(mActivity);
}
}
private void setResult() {
Intent result = null;
result = new Intent();
result.putExtra(KEY_RETURN_INDEX_HINT, mCurrentIndex);
setStateResult(Activity.RESULT_OK, result);
}
//////////////////////////////////////////////////////////////////////////
// AppBridge.Server interface
//////////////////////////////////////////////////////////////////////////
@Override
public void setCameraRelativeFrame(Rect frame) {
mPhotoView.setCameraRelativeFrame(frame);
}
@Override
public boolean switchWithCaptureAnimation(int offset) {
return mPhotoView.switchWithCaptureAnimation(offset);
}
@Override
public void setSwipingEnabled(boolean enabled) {
mPhotoView.setSwipingEnabled(enabled);
}
@Override
public void notifyScreenNailChanged() {
mScreenNailItem.setScreenNail(mAppBridge.attachScreenNail());
mScreenNailSet.notifyChange();
}
@Override
public void addSecureAlbumItem(boolean isVideo, int id) {
mSecureAlbum.addMediaItem(isVideo, id);
}
@Override
protected boolean onCreateActionBar(Menu menu) {
mActionBar.createActionBarMenu(R.menu.photo, menu);
mHaveImageEditor = GalleryUtils.isEditorAvailable(mActivity, "image/*");
updateMenuOperations();
mActionBar.setTitle(mMediaSet != null ? mMediaSet.getName() : "");
return true;
}
private MenuExecutor.ProgressListener mConfirmDialogListener =
new MenuExecutor.ProgressListener() {
@Override
public void onProgressUpdate(int index) {}
@Override
public void onProgressComplete(int result) {}
@Override
public void onConfirmDialogShown() {
mHandler.removeMessages(MSG_HIDE_BARS);
}
@Override
public void onConfirmDialogDismissed(boolean confirmed) {
refreshHidingMessage();
}
@Override
public void onProgressStart() {}
};
private void switchToGrid() {
if (mActivity.getStateManager().hasStateClass(AlbumPage.class)) {
onUpPressed();
} else {
if (mOriginalSetPathString == null) return;
Bundle data = new Bundle(getData());
data.putString(AlbumPage.KEY_MEDIA_PATH, mOriginalSetPathString);
data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH,
mActivity.getDataManager().getTopSetPath(
DataManager.INCLUDE_ALL));
// We only show cluster menu in the first AlbumPage in stack
// TODO: Enable this when running from the camera app
boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class);
data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum
&& mAppBridge == null);
data.putBoolean(PhotoPage.KEY_APP_BRIDGE, mAppBridge != null);
// Account for live preview being first item
mActivity.getTransitionStore().put(KEY_RETURN_INDEX_HINT,
mAppBridge != null ? mCurrentIndex - 1 : mCurrentIndex);
if (mHasCameraScreennailOrPlaceholder && mAppBridge != null) {
mActivity.getStateManager().startState(AlbumPage.class, data);
} else {
mActivity.getStateManager().switchState(this, AlbumPage.class, data);
}
}
}
@Override
protected boolean onItemSelected(MenuItem item) {
if (mModel == null) return true;
refreshHidingMessage();
MediaItem current = mModel.getMediaItem(0);
// This is a shield for monkey when it clicks the action bar
// menu when transitioning from filmstrip to camera
if (current instanceof SnailItem) return true;
// TODO: We should check the current photo against the MediaItem
// that the menu was initially created for. We need to fix this
// after PhotoPage being refactored.
if (current == null) {
// item is not ready, ignore
return true;
}
int currentIndex = mModel.getCurrentIndex();
// If RTL, the current index need be revised.
if (View.LAYOUT_DIRECTION_RTL == TextUtils
.getLayoutDirectionFromLocale(Locale.getDefault())) {
currentIndex = mMediaSet.getMediaItemCount() - currentIndex - 1;
}
Path path = current.getPath();
DataManager manager = mActivity.getDataManager();
int action = item.getItemId();
String confirmMsg = null;
switch (action) {
case android.R.id.home: {
onUpPressed();
return true;
}
case R.id.action_slideshow: {
Bundle data = new Bundle();
data.putString(SlideshowPage.KEY_SET_PATH, mMediaSet.getPath().toString());
data.putString(SlideshowPage.KEY_ITEM_PATH, path.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 = mActivity;
Intent intent = new Intent(CropActivity.CROP_ACTION);
intent.setClass(activity, CropActivity.class);
intent.setDataAndType(manager.getContentUri(path), current.getMimeType())
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivityForResult(intent, PicasaSource.isPicasaImage(current)
? REQUEST_CROP_PICASA
: REQUEST_CROP);
return true;
}
case R.id.action_trim: {
Intent intent = new Intent(mActivity, TrimVideo.class);
intent.setData(manager.getContentUri(path));
// We need the file path to wrap this into a RandomAccessFile.
String str = android.media.MediaFile.getMimeTypeForFile(current.getFilePath());
if("video/mp4".equals(str) || "video/mpeg4".equals(str)
|| "video/3gpp".equals(str) || "video/3gpp2".equals(str)) {
intent.putExtra(KEY_MEDIA_ITEM_PATH, current.getFilePath());
mActivity.startActivityForResult(intent, REQUEST_TRIM);
} else {
Toast.makeText(mActivity,mActivity.getString(R.string.can_not_trim),
Toast.LENGTH_SHORT).show();
}
return true;
}
case R.id.action_mute: {
MuteVideo muteVideo = new MuteVideo(current.getFilePath(),
manager.getContentUri(path), mActivity);
muteVideo.muteInBackground();
return true;
}
case R.id.action_edit: {
launchPhotoEditor();
return true;
}
case R.id.action_simple_edit: {
launchSimpleEditor();
return true;
}
case R.id.action_details: {
if (mShowDetails) {
hideDetails();
} else {
showDetails();
}
return true;
}
case R.id.print: {
mActivity.printSelectedImage(manager.getContentUri(path));
return true;
}
case R.id.action_delete:
confirmMsg = mActivity.getResources().getQuantityString(
R.plurals.delete_selection, 1);
case R.id.action_setas:
case R.id.action_rotate_ccw:
case R.id.action_rotate_cw:
case R.id.action_show_on_map:
mSelectionManager.deSelectAll();
mSelectionManager.toggle(path);
mMenuExecutor.onMenuClicked(item, confirmMsg, mConfirmDialogListener);
return true;
case R.id.action_drm_info:
String filepath = current.getFilePath();
if (DrmHelper.isDrmFile(filepath)) {
DrmHelper.showDrmInfo(mActivity.getAndroidContext(), filepath);
}
return true;
default :
return false;
}
}
private void hideDetails() {
mShowDetails = false;
mDetailsHelper.hide();
}
private void showDetails() {
mShowDetails = true;
if (mDetailsHelper == null) {
mDetailsHelper = new DetailsHelper(mActivity, mRootPane, new MyDetailsSource());
mDetailsHelper.setCloseListener(new CloseListener() {
@Override
public void onClose() {
hideDetails();
}
});
}
mDetailsHelper.show();
}
////////////////////////////////////////////////////////////////////////////
// Callbacks from PhotoView
////////////////////////////////////////////////////////////////////////////
@Override
public void onSingleTapUp(int x, int y) {
if (mAppBridge != null) {
if (mAppBridge.onSingleTapUp(x, y)) return;
}
MediaItem item = mModel.getMediaItem(0);
if (item == null || item == mScreenNailItem) {
// item is not ready or it is camera preview, ignore
return;
}
if (item.getMimeType().equals(MediaItem.MIME_TYPE_GIF)) {
viewAnimateGif((Activity) mActivity, item.getContentUri());
return;
}
int supported = item.getSupportedOperations();
boolean playVideo = ((supported & MediaItem.SUPPORT_PLAY) != 0);
boolean unlock = ((supported & MediaItem.SUPPORT_UNLOCK) != 0);
boolean goBack = ((supported & MediaItem.SUPPORT_BACK) != 0);
boolean launchCamera = ((supported & MediaItem.SUPPORT_CAMERA_SHORTCUT) != 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) {
if (mSecureAlbum == null) {
playVideo(mActivity, item.getPlayUri(), item.getName());
} else {
mActivity.getStateManager().finishState(this);
}
} else if (goBack) {
onBackPressed();
} else if (unlock) {
Intent intent = new Intent(mActivity, GalleryActivity.class);
intent.putExtra(GalleryActivity.KEY_DISMISS_KEYGUARD, true);
mActivity.startActivity(intent);
} else if (launchCamera) {
launchCamera();
} else {
toggleBars();
}
}
@Override
public void onActionBarAllowed(boolean allowed) {
mActionBarAllowed = allowed;
mHandler.sendEmptyMessage(MSG_UPDATE_ACTION_BAR);
}
@Override
public void onActionBarWanted() {
mHandler.sendEmptyMessage(MSG_WANT_BARS);
}
@Override
public void onFullScreenChanged(boolean full) {
Message m = mHandler.obtainMessage(
MSG_ON_FULL_SCREEN_CHANGED, full ? 1 : 0, 0);
m.sendToTarget();
}
// How we do delete/undo:
//
// When the user choose to delete a media item, we just tell the
// FilterDeleteSet to hide that item. If the user choose to undo it, we
// again tell FilterDeleteSet not to hide it. If the user choose to commit
// the deletion, we then actually delete the media item.
@Override
public void onDeleteImage(Path path, int offset) {
onCommitDeleteImage(); // commit the previous deletion
mDeletePath = path;
mDeleteIsFocus = (offset == 0);
// If RTL, the index need be revised.
if (View.LAYOUT_DIRECTION_RTL == TextUtils
.getLayoutDirectionFromLocale(Locale.getDefault())) {
mMediaSet.addDeletion(path, mMediaSet.getMediaItemCount() - mCurrentIndex - 1);
} else {
mMediaSet.addDeletion(path, mCurrentIndex + offset);
}
}
@Override
public void onUndoDeleteImage() {
if (mDeletePath == null) return;
// If the deletion was done on the focused item, we want the model to
// focus on it when it is undeleted.
if (mDeleteIsFocus) mModel.setFocusHintPath(mDeletePath);
mMediaSet.removeDeletion(mDeletePath);
mDeletePath = null;
}
@Override
public void onCommitDeleteImage() {
if (mDeletePath == null) return;
mMenuExecutor.startSingleItemAction(R.id.action_delete, mDeletePath);
mDeletePath = null;
}
public void playVideo(Activity activity, Uri uri, String title) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW)
.setDataAndType(uri, "video/*")
.putExtra(Intent.EXTRA_TITLE, title)
.putExtra(MovieActivity.KEY_TREAT_UP_AS_BACK, true);
activity.startActivityForResult(intent, REQUEST_PLAY_VIDEO);
} catch (ActivityNotFoundException e) {
Toast.makeText(activity, activity.getString(R.string.video_err),
Toast.LENGTH_SHORT).show();
}
}
private void setCurrentPhotoByIntent(Intent intent) {
if (intent == null) return;
Path path = mApplication.getDataManager()
.findPathByUri(intent.getData(), intent.getType());
if (path != null) {
Path albumPath = mApplication.getDataManager().getDefaultSetOf(path);
if (albumPath == null) {
return;
}
if (!albumPath.equalsIgnoreCase(mOriginalSetPathString)) {
// If the edited image is stored in a different album, we need
// to start a new activity state to show the new image
Bundle data = new Bundle(getData());
data.putString(KEY_MEDIA_SET_PATH, albumPath.toString());
data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, path.toString());
mActivity.getStateManager().startState(SinglePhotoPage.class, data);
return;
}
mModel.setCurrentPhoto(path, mCurrentIndex);
}
}
@Override
protected void onStateResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_CANCELED) {
// This is a reset, not a canceled
return;
}
mRecenterCameraOnResume = false;
switch (requestCode) {
case REQUEST_EDIT:
setCurrentPhotoByIntent(data);
break;
case REQUEST_CROP:
if (resultCode == Activity.RESULT_OK) {
setCurrentPhotoByIntent(data);
}
break;
case REQUEST_CROP_PICASA: {
if (resultCode == Activity.RESULT_OK) {
Context context = mActivity.getAndroidContext();
String message = context.getString(R.string.crop_saved,
context.getString(R.string.folder_edited_online_photos));
Toast.makeText(context, 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 RTL, the index need be revised.
if (View.LAYOUT_DIRECTION_RTL == TextUtils
.getLayoutDirectionFromLocale(Locale.getDefault())) {
index = mMediaSet.getMediaItemCount() - index - 1;
}
if (path != null) {
mModel.setCurrentPhoto(Path.fromString(path), index);
}
}
}
}
@Override
public void onPause() {
super.onPause();
mIsActive = false;
mActivity.getGLRoot().unfreeze();
mHandler.removeMessages(MSG_UNFREEZE_GLROOT);
DetailsHelper.pause();
// Hide the detail dialog on exit
if (mShowDetails) hideDetails();
if (mModel != null) {
mModel.pause();
}
mPhotoView.pause();
mHandler.removeMessages(MSG_HIDE_BARS);
mHandler.removeMessages(MSG_REFRESH_BOTTOM_CONTROLS);
refreshBottomControlsWhenReady();
mActionBar.removeOnMenuVisibilityListener(mMenuVisibilityListener);
if (mShowSpinner) {
mActionBar.disableAlbumModeMenu(true);
}
onCommitDeleteImage();
mMenuExecutor.pause();
if (mMediaSet != null) mMediaSet.clearDeletion();
}
@Override
public void onCurrentImageUpdated() {
mActivity.getGLRoot().unfreeze();
}
@Override
public void onFilmModeChanged(boolean enabled) {
refreshBottomControlsWhenReady();
if (mShowSpinner) {
if (enabled) {
mActionBar.enableAlbumModeMenu(
GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED, this);
} else {
mActionBar.disableAlbumModeMenu(true);
}
}
if (enabled) {
mHandler.removeMessages(MSG_HIDE_BARS);
UsageStatistics.onContentViewChanged(
UsageStatistics.COMPONENT_GALLERY, "FilmstripPage");
} else {
refreshHidingMessage();
if (mAppBridge == null || mCurrentIndex > 0) {
UsageStatistics.onContentViewChanged(
UsageStatistics.COMPONENT_GALLERY, "SinglePhotoPage");
} else {
UsageStatistics.onContentViewChanged(
UsageStatistics.COMPONENT_CAMERA, "Unknown"); // TODO
}
// Manage DRM rights while image selection changed. this
// flow will comes for both image and video, but here
// we will consume rights for image files only.
// Do not consume rights of a GIF image and video here.
// ViewGifImage will take care of GIF rights consumption stub.
// MediaPlayer will handle the video rights consumption stub.
if ((mMediaSet != null && mMediaSet.getMediaItemCount() > 1)
|| !(this instanceof SinglePhotoPage)) {
String mime = mCurrentPhoto.getMimeType();
if (!TextUtils.isEmpty(mime) && !mime.equals("image/gif")
&& !mime.startsWith("video/")) {
DrmHelper.manageDrmLicense(mActivity.getAndroidContext(),
mHandler, mCurrentPhoto.getFilePath(),
mCurrentPhoto.getMimeType());
}
}
}
}
private void transitionFromAlbumPageIfNeeded() {
TransitionStore transitions = mActivity.getTransitionStore();
int albumPageTransition = transitions.get(
KEY_ALBUMPAGE_TRANSITION, MSG_ALBUMPAGE_NONE);
if (albumPageTransition == MSG_ALBUMPAGE_NONE && mAppBridge != null
&& mRecenterCameraOnResume) {
// Generally, resuming the PhotoPage when in Camera should
// reset to the capture mode to allow quick photo taking
mCurrentIndex = 0;
mPhotoView.resetToFirstPicture();
} else {
int resumeIndex = transitions.get(KEY_INDEX_HINT, -1);
if (resumeIndex >= 0) {
if (mHasCameraScreennailOrPlaceholder) {
// Account for preview/placeholder being the first item
resumeIndex++;
}
if (resumeIndex < mMediaSet.getMediaItemCount()) {
mCurrentIndex = resumeIndex;
mModel.moveTo(mCurrentIndex);
}
}
}
if (albumPageTransition == MSG_ALBUMPAGE_RESUMED) {
mPhotoView.setFilmMode(mStartInFilmstrip || mAppBridge != null);
} else if (albumPageTransition == MSG_ALBUMPAGE_PICKED) {
mPhotoView.setFilmMode(false);
}
}
@Override
public void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
if(mIsActive) return;
mActivity.GLRootResume(true);
mModel.resume();
mActivity.GLRootResume(false);
}
@Override
protected void onResume() {
super.onResume();
if (mModel == null) {
mActivity.getStateManager().finishState(this);
return;
}
transitionFromAlbumPageIfNeeded();
mActivity.getGLRoot().freeze();
mIsActive = true;
setContentPane(mRootPane);
mModel.resume();
mPhotoView.resume();
mActionBar.setDisplayOptions(
((mSecureAlbum == null) && (mSetPathString != null)), false);
mActionBar.addOnMenuVisibilityListener(mMenuVisibilityListener);
refreshBottomControlsWhenReady();
if (mShowSpinner && mPhotoView.getFilmMode()) {
mActionBar.enableAlbumModeMenu(
GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED, this);
}
if (!mShowBars) {
mActionBar.hide();
mActivity.getGLRoot().setLightsOutMode(true);
}
boolean haveImageEditor = GalleryUtils.isEditorAvailable(mActivity, "image/*");
if (haveImageEditor != mHaveImageEditor) {
mHaveImageEditor = haveImageEditor;
updateMenuOperations();
}
mRecenterCameraOnResume = true;
mHandler.sendEmptyMessageDelayed(MSG_UNFREEZE_GLROOT, UNFREEZE_GLROOT_TIMEOUT);
}
@Override
protected void onDestroy() {
if (mAppBridge != null) {
mAppBridge.setServer(null);
mScreenNailItem.setScreenNail(null);
mAppBridge.detachScreenNail();
mAppBridge = null;
mScreenNailSet = null;
mScreenNailItem = null;
}
mActivity.getGLRoot().setOrientationSource(null);
if (mBottomControls != null) mBottomControls.cleanup();
// Remove all pending messages.
mHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
private class MyDetailsSource implements DetailsSource {
@Override
public MediaDetails getDetails() {
return mModel.getMediaItem(0).getDetails();
}
@Override
public int size() {
return mMediaSet != null ? mMediaSet.getMediaItemCount() : 1;
}
@Override
public int setIndex() {
return mModel.getCurrentIndex();
}
}
@Override
public void onAlbumModeSelected(int mode) {
if (mode == GalleryActionBar.ALBUM_GRID_MODE_SELECTED) {
switchToGrid();
}
}
@Override
public void refreshBottomControlsWhenReady() {
if (mBottomControls == null) {
return;
}
MediaObject currentPhoto = mCurrentPhoto;
if (currentPhoto == null) {
mHandler.obtainMessage(MSG_REFRESH_BOTTOM_CONTROLS, 0, 0, currentPhoto).sendToTarget();
} else {
currentPhoto.getPanoramaSupport(mRefreshBottomControlsCallback);
}
}
private void updatePanoramaUI(boolean isPanorama360) {
Menu menu = mActionBar.getMenu();
// it could be null if onCreateActionBar has not been called yet
if (menu == null) {
return;
}
MenuExecutor.updateMenuForPanorama(menu, isPanorama360, isPanorama360);
if (isPanorama360) {
MenuItem item = menu.findItem(R.id.action_share);
if (item != null) {
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
item.setTitle(mActivity.getResources().getString(R.string.share_as_photo));
}
} else if ((mCurrentPhoto.getSupportedOperations() & MediaObject.SUPPORT_SHARE) != 0) {
MenuItem item = menu.findItem(R.id.action_share);
if (item != null) {
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
item.setTitle(mActivity.getResources().getString(R.string.share));
}
}
}
@Override
public void onUndoBarVisibilityChanged(boolean visible) {
refreshBottomControlsWhenReady();
}
@Override
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent) {
final long timestampMillis = mCurrentPhoto.getDateInMs();
final String mediaType = getMediaTypeString(mCurrentPhoto);
UsageStatistics.onEvent(UsageStatistics.COMPONENT_GALLERY,
UsageStatistics.ACTION_SHARE,
mediaType,
timestampMillis > 0
? System.currentTimeMillis() - timestampMillis
: -1);
return false;
}
private static String getMediaTypeString(MediaItem item) {
if (item.getMediaType() == MediaObject.MEDIA_TYPE_VIDEO) {
return "Video";
} else if (item.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE) {
return "Photo";
} else {
return "Unknown:" + item.getMediaType();
}
}
private static void viewAnimateGif(Activity activity, Uri uri) {
Intent intent = new Intent(ViewGifImage.VIEW_GIF_ACTION, uri);
if (DrmHelper.isDrmFile(uri.toString())) {
intent.setDataAndType(uri, "image/gif");
}
activity.startActivity(intent);
}
}