diff options
author | George Mount <mount@google.com> | 2012-10-18 16:54:27 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-10-18 16:54:28 -0700 |
commit | 10ed0fbdb5619d0972aa3cc6fd8c05201a992e39 (patch) | |
tree | c9329a3f339edf9d27b2d5df1773f23453d65dc9 | |
parent | 6fae731dfab7861a878a853358a06db71399b3e8 (diff) | |
parent | 16b3bfbbd2a6447684ac406554f862b29c873751 (diff) | |
download | android_packages_apps_Snap-10ed0fbdb5619d0972aa3cc6fd8c05201a992e39.tar.gz android_packages_apps_Snap-10ed0fbdb5619d0972aa3cc6fd8c05201a992e39.tar.bz2 android_packages_apps_Snap-10ed0fbdb5619d0972aa3cc6fd8c05201a992e39.zip |
Merge "Remove panorama checks from supported operations." into gb-ub-photos-arches
-rw-r--r-- | src/com/android/gallery3d/app/GalleryAppImpl.java | 1 | ||||
-rw-r--r-- | src/com/android/gallery3d/app/PanoramaMetadataSupport.java | 89 | ||||
-rw-r--r-- | src/com/android/gallery3d/app/PhotoPage.java | 198 | ||||
-rw-r--r-- | src/com/android/gallery3d/app/PhotoPageBottomControls.java | 10 | ||||
-rw-r--r-- | src/com/android/gallery3d/data/DataManager.java | 33 | ||||
-rw-r--r-- | src/com/android/gallery3d/data/LocalImage.java | 66 | ||||
-rw-r--r-- | src/com/android/gallery3d/data/MediaObject.java | 23 | ||||
-rw-r--r-- | src/com/android/gallery3d/data/PanoramaMetadataJob.java | 2 | ||||
-rw-r--r-- | src/com/android/gallery3d/data/UriImage.java | 66 | ||||
-rw-r--r-- | src/com/android/gallery3d/ui/ActionModeHandler.java | 104 | ||||
-rw-r--r-- | src/com/android/gallery3d/ui/MenuExecutor.java | 14 | ||||
-rw-r--r-- | src_pd/com/android/gallery3d/util/LightCycleHelper.java | 4 |
12 files changed, 361 insertions, 249 deletions
diff --git a/src/com/android/gallery3d/app/GalleryAppImpl.java b/src/com/android/gallery3d/app/GalleryAppImpl.java index c4507b340..443bc47ee 100644 --- a/src/com/android/gallery3d/app/GalleryAppImpl.java +++ b/src/com/android/gallery3d/app/GalleryAppImpl.java @@ -63,6 +63,7 @@ public class GalleryAppImpl extends Application implements GalleryApp { state, PackageManager.DONT_KILL_APP); mStitchingProgressManager = LightCycleHelper.createStitchingManagerInstance(this); + mStitchingProgressManager.addChangeListener(getDataManager()); } @Override diff --git a/src/com/android/gallery3d/app/PanoramaMetadataSupport.java b/src/com/android/gallery3d/app/PanoramaMetadataSupport.java new file mode 100644 index 000000000..d40422582 --- /dev/null +++ b/src/com/android/gallery3d/app/PanoramaMetadataSupport.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012 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.data.MediaObject; +import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; +import com.android.gallery3d.data.PanoramaMetadataJob; +import com.android.gallery3d.util.Future; +import com.android.gallery3d.util.FutureListener; +import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata; + +import java.util.ArrayList; + +/** + * This class breaks out the off-thread panorama support checks so that the + * complexity can be shared between UriImage and LocalImage, which need to + * support panoramas. + */ +public class PanoramaMetadataSupport implements FutureListener<PanoramaMetadata> { + private Object mLock = new Object(); + private Future<PanoramaMetadata> mGetPanoMetadataTask; + private PanoramaMetadata mPanoramaMetadata; + private ArrayList<PanoramaSupportCallback> mCallbacksWaiting; + private MediaObject mMediaObject; + + public PanoramaMetadataSupport(MediaObject mediaObject) { + mMediaObject = mediaObject; + } + + public void getPanoramaSupport(GalleryApp app, PanoramaSupportCallback callback) { + synchronized (mLock) { + if (mPanoramaMetadata != null) { + callback.panoramaInfoAvailable(mMediaObject, mPanoramaMetadata.mUsePanoramaViewer, + mPanoramaMetadata.mIsPanorama360); + } else { + if (mCallbacksWaiting == null) { + mCallbacksWaiting = new ArrayList<PanoramaSupportCallback>(); + mGetPanoMetadataTask = app.getThreadPool().submit( + new PanoramaMetadataJob(app.getAndroidContext(), + mMediaObject.getContentUri()), this); + + } + mCallbacksWaiting.add(callback); + } + } + } + + public void clearCachedValues() { + synchronized (mLock) { + if (mPanoramaMetadata != null) { + mPanoramaMetadata = null; + } else if (mGetPanoMetadataTask != null) { + mGetPanoMetadataTask.cancel(); + for (PanoramaSupportCallback cb : mCallbacksWaiting) { + cb.panoramaInfoAvailable(mMediaObject, false, false); + } + mGetPanoMetadataTask = null; + mCallbacksWaiting = null; + } + } + } + + @Override + public void onFutureDone(Future<PanoramaMetadata> future) { + synchronized (mLock) { + mPanoramaMetadata = future.get(); + for (PanoramaSupportCallback cb : mCallbacksWaiting) { + cb.panoramaInfoAvailable(mMediaObject, + mPanoramaMetadata.mUsePanoramaViewer, + mPanoramaMetadata.mIsPanorama360); + } + mGetPanoMetadataTask = null; + mCallbacksWaiting = null; + } + } +} diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java index a548e704f..f900c408f 100644 --- a/src/com/android/gallery3d/app/PhotoPage.java +++ b/src/com/android/gallery3d/app/PhotoPage.java @@ -48,7 +48,7 @@ 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.SupportedOperationsListener; +import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; import com.android.gallery3d.data.MediaSet; import com.android.gallery3d.data.MtpSource; import com.android.gallery3d.data.Path; @@ -91,6 +91,8 @@ public class PhotoPage extends ActivityState implements private static final int MSG_UPDATE_PHOTO_UI = 12; private static final int MSG_UPDATE_PROGRESS = 13; 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; @@ -166,7 +168,7 @@ public class PhotoPage extends ActivityState implements private boolean mSkipUpdateCurrentPhoto = false; private static final long CAMERA_SWITCH_CUTOFF_THRESHOLD_MS = 300; - private static final long DEFERRED_UPDATE_MS = 150; + private static final long DEFERRED_UPDATE_MS = 250; private boolean mDeferredUpdateWaiting = false; private long mDeferUpdateUntil = Long.MAX_VALUE; @@ -182,20 +184,37 @@ public class PhotoPage extends ActivityState implements new MyMenuVisibilityListener(); private UpdateProgressListener mProgressListener; - private SupportedOperationsListener mSupportedOperationsListener = - new SupportedOperationsListener() { - @Override - public void onChange(MediaObject item, int operations) { - if (item == mCurrentPhoto) { - if (mPhotoView.getFilmMode() - && SystemClock.uptimeMillis() < mDeferUpdateUntil) { - requestDeferredUpdate(); - } else { - mHandler.sendEmptyMessage(MSG_UPDATE_PHOTO_UI); - } - } + 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, 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(); @@ -230,8 +249,9 @@ public class PhotoPage extends ActivityState implements } private void sendUpdate(Uri uri, int message) { - boolean isCurrentPhoto = mCurrentPhoto instanceof LocalImage - && mCurrentPhoto.getContentUri().equals(uri); + MediaObject currentPhoto = mCurrentPhoto; + boolean isCurrentPhoto = currentPhoto instanceof LocalImage + && currentPhoto.getContentUri().equals(uri); if (isCurrentPhoto) { mHandler.sendEmptyMessage(message); } @@ -278,7 +298,9 @@ public class PhotoPage extends ActivityState implements break; } case MSG_REFRESH_BOTTOM_CONTROLS: { - if (mBottomControls != null) mBottomControls.refresh(); + if (mCurrentPhoto == message.obj && mBottomControls != null) { + mBottomControls.refresh(message.arg1 != 0); + } break; } case MSG_ON_FULL_SCREEN_CHANGED: { @@ -347,6 +369,28 @@ public class PhotoPage extends ActivityState implements updateProgressBar(); 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); + + mActionBar.setShareIntents(panoramaIntent, shareIntent); + 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); } } @@ -540,18 +584,17 @@ public class PhotoPage extends ActivityState implements } @Override - public boolean canDisplayBottomControl(int control) { - if (mCurrentPhoto == null) return false; + public boolean canDisplayBottomControl(int control, boolean isPanorama) { + if (mCurrentPhoto == null) { + return false; + } switch(control) { case R.id.photopage_bottom_control_edit: return mHaveImageEditor && mShowBars - && (mCurrentPhoto.getSupportedOperations() - & MediaItem.SUPPORT_EDIT) != 0 - && mCurrentPhoto.getMediaType() - == MediaObject.MEDIA_TYPE_IMAGE; + && (mCurrentPhoto.getSupportedOperations() & MediaItem.SUPPORT_EDIT) != 0 + && mCurrentPhoto.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE; case R.id.photopage_bottom_control_panorama: - return (mCurrentPhoto.getSupportedOperations() - & MediaItem.SUPPORT_PANORAMA) != 0; + return isPanorama; default: return false; } @@ -593,24 +636,18 @@ public class PhotoPage extends ActivityState implements mNfcPushUris[0] = uri; } - private Intent createShareIntent(Path path) { - DataManager manager = mActivity.getDataManager(); - int type = manager.getMediaType(path); + private static Intent createShareIntent(MediaObject mediaObject) { + int type = mediaObject.getMediaType(); return new Intent(Intent.ACTION_SEND) .setType(MenuExecutor.getMimeType(type)) - .putExtra(Intent.EXTRA_STREAM, manager.getContentUri(path)) + .putExtra(Intent.EXTRA_STREAM, mediaObject.getContentUri()) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } - private Intent createSharePanoramaIntent(Path path) { - DataManager manager = mActivity.getDataManager(); - int supported = manager.getSupportedOperations(path); - if ((supported & MediaObject.SUPPORT_PANORAMA360) == 0) { - return null; - } + private static Intent createSharePanoramaIntent(Uri contentUri) { return new Intent(Intent.ACTION_SEND) .setType(GalleryUtils.MIME_TYPE_PANORAMA360) - .putExtra(Intent.EXTRA_STREAM, manager.getContentUri(path)) + .putExtra(Intent.EXTRA_STREAM, contentUri) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } @@ -634,15 +671,6 @@ public class PhotoPage extends ActivityState implements REQUEST_EDIT); } - private void updateShareURI(Path path) { - DataManager manager = mActivity.getDataManager(); - mActionBar.setShareIntents( - createSharePanoramaIntent(path), - createShareIntent(path)); - Uri uri = manager.getContentUri(path); - setNfcBeamPushUri(uri); - } - private void requestDeferredUpdate() { mDeferUpdateUntil = SystemClock.uptimeMillis() + DEFERRED_UPDATE_MS; if (!mDeferredUpdateWaiting) { @@ -663,25 +691,20 @@ public class PhotoPage extends ActivityState implements } updateMenuOperations(); - if (mBottomControls != null) mBottomControls.refresh(); + refreshBottomControlsWhenReady(); if (mShowDetails) { mDetailsHelper.reloadDetails(); } if ((mSecureAlbum == null) && (mCurrentPhoto.getSupportedOperations() & MediaItem.SUPPORT_SHARE) != 0) { - updateShareURI(mCurrentPhoto.getPath()); + mCurrentPhoto.getPanoramaSupport(mUpdateShareURICallback); } updateProgressBar(); } private void updateCurrentPhoto(MediaItem photo) { if (mCurrentPhoto == photo) return; - if (mCurrentPhoto != null) { - mCurrentPhoto.setSupportedOperationsListener(null); - } mCurrentPhoto = photo; - mCurrentPhoto.setSupportedOperationsListener( - mSupportedOperationsListener); if (mPhotoView.getFilmMode()) { requestDeferredUpdate(); } else { @@ -721,22 +744,7 @@ public class PhotoPage extends ActivityState implements supportedOperations &= ~MediaObject.SUPPORT_EDIT; } MenuExecutor.updateMenuOperation(menu, supportedOperations); - if ((supportedOperations & MediaObject.SUPPORT_PANORAMA360) != 0) { - mActivity.invalidateOptionsMenu(); - 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 ((supportedOperations & MediaObject.SUPPORT_SHARE) != 0) { - 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)); - } - } + mCurrentPhoto.getPanoramaSupport(mUpdatePanoramaMenuItemsCallback); } private boolean canDoSlideShow() { @@ -763,7 +771,7 @@ public class PhotoPage extends ActivityState implements mActionBar.show(); mActivity.getGLRoot().setLightsOutMode(false); refreshHidingMessage(); - if (mBottomControls != null) mBottomControls.refresh(); + refreshBottomControlsWhenReady(); } private void hideBars() { @@ -772,7 +780,7 @@ public class PhotoPage extends ActivityState implements mActionBar.hide(); mActivity.getGLRoot().setLightsOutMode(true); mHandler.removeMessages(MSG_HIDE_BARS); - if (mBottomControls != null) mBottomControls.refresh(); + refreshBottomControlsWhenReady(); } private void refreshHidingMessage() { @@ -1283,9 +1291,7 @@ public class PhotoPage extends ActivityState implements mPhotoView.pause(); mHandler.removeMessages(MSG_HIDE_BARS); mHandler.removeMessages(MSG_REFRESH_BOTTOM_CONTROLS); - if (mBottomControls != null) { - mBottomControls.refresh(); - } + refreshBottomControlsWhenReady(); mActionBar.removeOnMenuVisibilityListener(mMenuVisibilityListener); if (mShowSpinner) { mActionBar.disableAlbumModeMenu(true); @@ -1302,7 +1308,7 @@ public class PhotoPage extends ActivityState implements @Override public void onFilmModeChanged(boolean enabled) { - mHandler.sendEmptyMessage(MSG_REFRESH_BOTTOM_CONTROLS); + refreshBottomControlsWhenReady(); if (enabled) { mHandler.removeMessages(MSG_HIDE_BARS); } else { @@ -1362,9 +1368,7 @@ public class PhotoPage extends ActivityState implements mActionBar.setDisplayOptions( ((mSecureAlbum == null) && (mSetPathString != null)), false); mActionBar.addOnMenuVisibilityListener(mMenuVisibilityListener); - if (mBottomControls != null) { - mBottomControls.refresh(); - } + refreshBottomControlsWhenReady(); if (mShowSpinner) { mActionBar.enableAlbumModeMenu( GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED, this); @@ -1427,4 +1431,42 @@ public class PhotoPage extends ActivityState implements 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)); + } + } + } } diff --git a/src/com/android/gallery3d/app/PhotoPageBottomControls.java b/src/com/android/gallery3d/app/PhotoPageBottomControls.java index 40588e128..e58e454ac 100644 --- a/src/com/android/gallery3d/app/PhotoPageBottomControls.java +++ b/src/com/android/gallery3d/app/PhotoPageBottomControls.java @@ -23,7 +23,6 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; -import android.view.animation.ScaleAnimation; import android.widget.RelativeLayout; import com.android.gallery3d.R; @@ -34,8 +33,9 @@ import java.util.Map; public class PhotoPageBottomControls implements OnClickListener { public interface Delegate { public boolean canDisplayBottomControls(); - public boolean canDisplayBottomControl(int control); + public boolean canDisplayBottomControl(int control, boolean isPanorama); public void onBottomControlClicked(int control); + public void refreshBottomControlsWhenReady(); } private Delegate mDelegate; @@ -76,7 +76,7 @@ public class PhotoPageBottomControls implements OnClickListener { mContainerAnimIn.setDuration(CONTAINER_ANIM_DURATION_MS); mContainerAnimOut.setDuration(CONTAINER_ANIM_DURATION_MS); - refresh(); + mDelegate.refreshBottomControlsWhenReady(); } private void hide() { @@ -93,7 +93,7 @@ public class PhotoPageBottomControls implements OnClickListener { mContainer.setVisibility(View.VISIBLE); } - public void refresh() { + public void refresh(boolean isPanorama) { boolean visible = mDelegate.canDisplayBottomControls(); boolean containerVisibilityChanged = (visible != mContainerVisible); if (containerVisibilityChanged) { @@ -109,7 +109,7 @@ public class PhotoPageBottomControls implements OnClickListener { } for (View control : mControlsVisible.keySet()) { Boolean prevVisibility = mControlsVisible.get(control); - boolean curVisibility = mDelegate.canDisplayBottomControl(control.getId()); + boolean curVisibility = mDelegate.canDisplayBottomControl(control.getId(), isPanorama); if (prevVisibility.booleanValue() != curVisibility) { if (!containerVisibilityChanged) { control.clearAnimation(); diff --git a/src/com/android/gallery3d/data/DataManager.java b/src/com/android/gallery3d/data/DataManager.java index 408a24b13..4ec7b6d98 100644 --- a/src/com/android/gallery3d/data/DataManager.java +++ b/src/com/android/gallery3d/data/DataManager.java @@ -16,15 +16,15 @@ package com.android.gallery3d.data; -import android.content.Intent; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; -import android.support.v4.content.LocalBroadcastManager; import com.android.gallery3d.app.GalleryApp; +import com.android.gallery3d.app.StitchingChangeListener; import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.Utils; +import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; import com.android.gallery3d.data.MediaSet.ItemConsumer; import com.android.gallery3d.data.MediaSource.PathId; import com.android.gallery3d.picasasource.PicasaSource; @@ -49,7 +49,7 @@ import java.util.WeakHashMap; // path. And it's used to identify a specific media set even if the process is // killed and re-created, so child keys should be stable identifiers. -public class DataManager { +public class DataManager implements StitchingChangeListener { public static final int INCLUDE_IMAGE = 1; public static final int INCLUDE_VIDEO = 2; public static final int INCLUDE_ALL = INCLUDE_IMAGE | INCLUDE_VIDEO; @@ -247,10 +247,8 @@ public class DataManager { return getMediaObject(path).getSupportedOperations(); } - // getAll will cause this call to wait if any of the operations - // are expensive to compute. Do not call in UI thread. - public int getSupportedOperations(Path path, boolean getAll) { - return getMediaObject(path).getSupportedOperations(getAll); + public void getPanoramaSupport(Path path, PanoramaSupportCallback callback) { + getMediaObject(path).getPanoramaSupport(callback); } public void delete(Path path) { @@ -351,4 +349,25 @@ public class DataManager { } } } + + @Override + public void onStitchingQueued(Uri uri) { + // Do nothing. + } + + @Override + public void onStitchingResult(Uri uri) { + Path path = findPathByUri(uri, null); + if (path != null) { + MediaObject mediaObject = getMediaObject(path); + if (mediaObject != null) { + mediaObject.clearCachedPanoramaSupport(); + } + } + } + + @Override + public void onStitchingProgress(Uri uri, int progress) { + // Do nothing. + } } diff --git a/src/com/android/gallery3d/data/LocalImage.java b/src/com/android/gallery3d/data/LocalImage.java index 61961d87a..b2be1246a 100644 --- a/src/com/android/gallery3d/data/LocalImage.java +++ b/src/com/android/gallery3d/data/LocalImage.java @@ -19,7 +19,6 @@ package com.android.gallery3d.data; import android.annotation.TargetApi; import android.content.ContentResolver; import android.content.ContentValues; -import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -33,14 +32,11 @@ import android.provider.MediaStore.MediaColumns; import android.util.Log; import com.android.gallery3d.app.GalleryApp; +import com.android.gallery3d.app.PanoramaMetadataSupport; import com.android.gallery3d.app.StitchingProgressManager; import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.BitmapUtils; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.LightCycleHelper; -import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata; import com.android.gallery3d.util.ThreadPool.Job; import com.android.gallery3d.util.ThreadPool.JobContext; import com.android.gallery3d.util.UpdateHelper; @@ -104,11 +100,7 @@ public class LocalImage extends LocalMediaItem { public int rotation; - private Object mLock = new Object(); - private Future<PanoramaMetadata> mGetPanoMetadataTask; - private boolean mPanoramaMetadataInitialized; - private PanoramaMetadata mPanoramaMetadata; - private SupportedOperationsListener mListener; + private PanoramaMetadataSupport mPanoramaMetadata = new PanoramaMetadataSupport(this); public LocalImage(Path path, GalleryApp application, Cursor cursor) { super(path, nextVersionNumber()); @@ -257,63 +249,17 @@ public class LocalImage extends LocalMediaItem { if (GalleryUtils.isValidLocation(latitude, longitude)) { operation |= SUPPORT_SHOW_ON_MAP; } - - if (mPanoramaMetadata != null && mPanoramaMetadata.mUsePanoramaViewer) { - operation |= SUPPORT_PANORAMA; - if (mPanoramaMetadata.mIsPanorama360) { - operation |= SUPPORT_PANORAMA360; - // disable destructive rotate and crop for 360 degree panorama - operation &= ~(SUPPORT_ROTATE | SUPPORT_CROP); - } - } return operation; } @Override - public int getSupportedOperations(boolean getAll) { - synchronized (mLock) { - if (getAll && !mPanoramaMetadataInitialized) { - if (mGetPanoMetadataTask == null) { - mGetPanoMetadataTask = getThreadPool().submit( - new PanoramaMetadataJob(mApplication.getAndroidContext(), - getContentUri())); - } - mPanoramaMetadata = mGetPanoMetadataTask.get(); - mPanoramaMetadataInitialized = true; - } - } - return getSupportedOperations(); + public void getPanoramaSupport(PanoramaSupportCallback callback) { + mPanoramaMetadata.getPanoramaSupport(mApplication, callback); } @Override - public void setSupportedOperationsListener(SupportedOperationsListener l) { - synchronized (mLock) { - if (l == null) { - if (mGetPanoMetadataTask != null) { - mGetPanoMetadataTask.cancel(); - mGetPanoMetadataTask = null; - } - } else { - if (mGetPanoMetadataTask == null) { - mGetPanoMetadataTask = getThreadPool().submit( - new PanoramaMetadataJob(mApplication.getAndroidContext(), - getContentUri()), - new FutureListener<PanoramaMetadata>() { - @Override - public void onFutureDone(Future<PanoramaMetadata> future) { - mGetPanoMetadataTask = null; - if (future.isCancelled()) return; - mPanoramaMetadata = future.get(); - mPanoramaMetadataInitialized = true; - if (mListener != null) { - mListener.onChange(LocalImage.this, getSupportedOperations()); - } - } - }); - } - } - mListener = l; - } + public void clearCachedPanoramaSupport() { + mPanoramaMetadata.clearCachedValues(); } @Override diff --git a/src/com/android/gallery3d/data/MediaObject.java b/src/com/android/gallery3d/data/MediaObject.java index 14cd5242a..a41b275fb 100644 --- a/src/com/android/gallery3d/data/MediaObject.java +++ b/src/com/android/gallery3d/data/MediaObject.java @@ -18,8 +18,6 @@ package com.android.gallery3d.data; import android.net.Uri; -import com.android.gallery3d.util.ThreadPool; - public abstract class MediaObject { @SuppressWarnings("unused") private static final String TAG = "MediaObject"; @@ -43,16 +41,8 @@ public abstract class MediaObject { public static final int SUPPORT_BACK = 1 << 14; public static final int SUPPORT_ACTION = 1 << 15; public static final int SUPPORT_CAMERA_SHORTCUT = 1 << 16; - // The panorama specific bits are expensive to compute. - // Use SupportedOperationsListener to request them. - public static final int SUPPORT_PANORAMA = 1 << 30; - public static final int SUPPORT_PANORAMA360 = 1 << 31; public static final int SUPPORT_ALL = 0xffffffff; - public static interface SupportedOperationsListener { - public void onChange(MediaObject item, int operations); - } - // These are the bits returned from getMediaType(): public static final int MEDIA_TYPE_UNKNOWN = 1; public static final int MEDIA_TYPE_IMAGE = 2; @@ -80,9 +70,9 @@ public abstract class MediaObject { protected final Path mPath; - private static ThreadPool sThreadPool = new ThreadPool(1, 1); - public static ThreadPool getThreadPool() { - return sThreadPool; + public interface PanoramaSupportCallback { + void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama, + boolean isPanorama360); } public MediaObject(Path path, long version) { @@ -99,12 +89,11 @@ public abstract class MediaObject { return 0; } - public int getSupportedOperations(boolean getAll) { - return getSupportedOperations(); + public void getPanoramaSupport(PanoramaSupportCallback callback) { + callback.panoramaInfoAvailable(this, false, false); } - public void setSupportedOperationsListener(SupportedOperationsListener l) { - // nothing to do + public void clearCachedPanoramaSupport() { } public void delete() { diff --git a/src/com/android/gallery3d/data/PanoramaMetadataJob.java b/src/com/android/gallery3d/data/PanoramaMetadataJob.java index e0a69c41f..ab99d6a81 100644 --- a/src/com/android/gallery3d/data/PanoramaMetadataJob.java +++ b/src/com/android/gallery3d/data/PanoramaMetadataJob.java @@ -24,7 +24,7 @@ import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata; import com.android.gallery3d.util.ThreadPool.Job; import com.android.gallery3d.util.ThreadPool.JobContext; -class PanoramaMetadataJob implements Job<PanoramaMetadata> { +public class PanoramaMetadataJob implements Job<PanoramaMetadata> { Context mContext; Uri mUri; diff --git a/src/com/android/gallery3d/data/UriImage.java b/src/com/android/gallery3d/data/UriImage.java index aaa36a917..e8875b572 100644 --- a/src/com/android/gallery3d/data/UriImage.java +++ b/src/com/android/gallery3d/data/UriImage.java @@ -17,7 +17,6 @@ package com.android.gallery3d.data; import android.content.ContentResolver; -import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory.Options; @@ -26,12 +25,9 @@ import android.net.Uri; import android.os.ParcelFileDescriptor; import com.android.gallery3d.app.GalleryApp; +import com.android.gallery3d.app.PanoramaMetadataSupport; import com.android.gallery3d.common.BitmapUtils; import com.android.gallery3d.common.Utils; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; -import com.android.gallery3d.util.LightCycleHelper; -import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata; import com.android.gallery3d.util.ThreadPool.CancelListener; import com.android.gallery3d.util.ThreadPool.Job; import com.android.gallery3d.util.ThreadPool.JobContext; @@ -59,12 +55,7 @@ public class UriImage extends MediaItem { private int mWidth; private int mHeight; private int mRotation; - - private Object mLock = new Object(); - private Future<PanoramaMetadata> mGetPanoMetadataTask; - private boolean mPanoramaMetadataInitialized; - private PanoramaMetadata mPanoramaMetadata; - private SupportedOperationsListener mListener; + private PanoramaMetadataSupport mPanoramaMetadata = new PanoramaMetadataSupport(this); private GalleryApp mApplication; @@ -225,62 +216,17 @@ public class UriImage extends MediaItem { if (BitmapUtils.isSupportedByRegionDecoder(mContentType)) { supported |= SUPPORT_FULL_IMAGE; } - if (mPanoramaMetadata != null && mPanoramaMetadata.mUsePanoramaViewer) { - supported |= SUPPORT_PANORAMA; - if (mPanoramaMetadata.mIsPanorama360) { - supported |= SUPPORT_PANORAMA360; - // disable destructive crop for 360 degree panorama - supported &= ~SUPPORT_CROP; - } - } return supported; } @Override - public int getSupportedOperations(boolean getAll) { - synchronized (mLock) { - if (getAll && !mPanoramaMetadataInitialized) { - if (mGetPanoMetadataTask == null) { - mGetPanoMetadataTask = getThreadPool().submit( - new PanoramaMetadataJob(mApplication.getAndroidContext(), - getContentUri())); - } - mPanoramaMetadata = mGetPanoMetadataTask.get(); - mPanoramaMetadataInitialized = true; - } - } - return getSupportedOperations(); + public void getPanoramaSupport(PanoramaSupportCallback callback) { + mPanoramaMetadata.getPanoramaSupport(mApplication, callback); } @Override - public void setSupportedOperationsListener(SupportedOperationsListener l) { - synchronized (mLock) { - if (l != null) { - if (mGetPanoMetadataTask != null) { - mGetPanoMetadataTask.cancel(); - mGetPanoMetadataTask = null; - } - } else { - if (mGetPanoMetadataTask == null) { - mGetPanoMetadataTask = getThreadPool().submit( - new PanoramaMetadataJob(mApplication.getAndroidContext(), - getContentUri()), - new FutureListener<PanoramaMetadata>() { - @Override - public void onFutureDone(Future<PanoramaMetadata> future) { - mGetPanoMetadataTask = null; - if (future.isCancelled()) return; - mPanoramaMetadata = future.get(); - mPanoramaMetadataInitialized = true; - if (mListener != null) { - mListener.onChange(UriImage.this, getSupportedOperations()); - } - } - }); - } - } - mListener = l; - } + public void clearCachedPanoramaSupport() { + mPanoramaMetadata.clearCachedValues(); } private boolean isSharable() { diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java index 3384b88e3..bb195c91e 100644 --- a/src/com/android/gallery3d/ui/ActionModeHandler.java +++ b/src/com/android/gallery3d/ui/ActionModeHandler.java @@ -38,6 +38,7 @@ import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.DataManager; import com.android.gallery3d.data.MediaObject; +import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; import com.android.gallery3d.data.Path; import com.android.gallery3d.ui.MenuExecutor.ProgressListener; import com.android.gallery3d.util.Future; @@ -54,8 +55,7 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi private static final int SUPPORT_MULTIPLE_MASK = MediaObject.SUPPORT_DELETE | MediaObject.SUPPORT_ROTATE | MediaObject.SUPPORT_SHARE - | MediaObject.SUPPORT_CACHE | MediaObject.SUPPORT_IMPORT - | MediaObject.SUPPORT_PANORAMA | MediaObject.SUPPORT_PANORAMA360; + | MediaObject.SUPPORT_CACHE | MediaObject.SUPPORT_IMPORT; public interface ActionModeListener { public boolean onActionItemClicked(MenuItem item); @@ -76,6 +76,49 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi private final Handler mMainHandler; private ActionMode mActionMode; + private static class GetAllPanoramaSupports implements PanoramaSupportCallback { + private int mNumInfoRequired; + private JobContext mJobContext; + public boolean mAllPanoramas = true; + public boolean mAllPanorama360 = true; + public boolean mHasPanorama360 = false; + private Object mLock = new Object(); + + public GetAllPanoramaSupports(ArrayList<MediaObject> mediaObjects, JobContext jc) { + mJobContext = jc; + mNumInfoRequired = mediaObjects.size(); + for (MediaObject mediaObject : mediaObjects) { + mediaObject.getPanoramaSupport(this); + } + } + + @Override + public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama, + boolean isPanorama360) { + synchronized (mLock) { + mNumInfoRequired--; + mAllPanoramas = isPanorama && mAllPanoramas; + mAllPanorama360 = isPanorama360 && mAllPanorama360; + mHasPanorama360 = mHasPanorama360 || isPanorama360; + if (mNumInfoRequired == 0 || mJobContext.isCancelled()) { + mLock.notifyAll(); + } + } + } + + public void waitForPanoramaSupport() { + synchronized (mLock) { + while (mNumInfoRequired != 0 && !mJobContext.isCancelled()) { + try { + mLock.wait(); + } catch (InterruptedException e) { + // May be a cancelled job context + } + } + } + } + } + public ActionModeHandler( AbstractGalleryActivity activity, SelectionManager selectionManager) { mActivity = Utils.checkNotNull(activity); @@ -211,28 +254,38 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi mSelectionManager.leaveSelectionMode(); } - // Menu options are determined by selection set itself. - // We cannot expand it because MenuExecuter executes it based on - // the selection set instead of the expanded result. - // e.g. LocalImage can be rotated but collections of them (LocalAlbum) can't. - private int computeMenuOptions(JobContext jc) { + private ArrayList<MediaObject> getSelectedMediaObjects(JobContext jc) { ArrayList<Path> unexpandedPaths = mSelectionManager.getSelected(false); if (unexpandedPaths.isEmpty()) { // This happens when starting selection mode from overflow menu // (instead of long press a media object) - return 0; + return null; } - int operation = MediaObject.SUPPORT_ALL; + ArrayList<MediaObject> selected = new ArrayList<MediaObject>(); DataManager manager = mActivity.getDataManager(); - int type = 0; for (Path path : unexpandedPaths) { - if (jc.isCancelled()) return 0; - int support = manager.getSupportedOperations(path, true); - type |= manager.getMediaType(path); + if (jc.isCancelled()) { + return null; + } + selected.add(manager.getMediaObject(path)); + } + + return selected; + } + // Menu options are determined by selection set itself. + // We cannot expand it because MenuExecuter executes it based on + // the selection set instead of the expanded result. + // e.g. LocalImage can be rotated but collections of them (LocalAlbum) can't. + private int computeMenuOptions(ArrayList<MediaObject> selected) { + int operation = MediaObject.SUPPORT_ALL; + int type = 0; + for (MediaObject mediaObject: selected) { + int support = mediaObject.getSupportedOperations(); + type |= mediaObject.getMediaType(); operation &= support; } - switch (unexpandedPaths.size()) { + switch (selected.size()) { case 1: final String mimeType = MenuExecutor.getMimeType(type); if (!GalleryUtils.isEditorAvailable(mActivity, mimeType)) { @@ -298,7 +351,7 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi final Intent intent = new Intent(); for (Path path : expandedPaths) { if (jc.isCancelled()) return null; - int support = manager.getSupportedOperations(path, true); + int support = manager.getSupportedOperations(path); type |= manager.getMediaType(path); if ((support & MediaObject.SUPPORT_SHARE) != 0) { @@ -346,21 +399,36 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi @Override public Void run(final JobContext jc) { // Pass1: Deal with unexpanded media object list for menu operation. - final int operation = computeMenuOptions(jc); + ArrayList<MediaObject> selected = getSelectedMediaObjects(jc); + if (selected == null) { + return null; + } + final int operation = computeMenuOptions(selected); + if (jc.isCancelled()) { + return null; + } + final GetAllPanoramaSupports supportCallback = new GetAllPanoramaSupports(selected, + jc); // Pass2: Deal with expanded media object list for sharing operation. final Intent share_panorama_intent = computePanoramaSharingIntent(jc); final Intent share_intent = computeSharingIntent(jc); + + supportCallback.waitForPanoramaSupport(); + if (jc.isCancelled()) { + return null; + } mMainHandler.post(new Runnable() { @Override public void run() { mMenuTask = null; if (jc.isCancelled()) return; MenuExecutor.updateMenuOperation(mMenu, operation); + MenuExecutor.updateMenuForPanorama(mMenu, supportCallback.mAllPanorama360, + supportCallback.mHasPanorama360); if (mSharePanoramaMenuItem != null) { mSharePanoramaMenuItem.setEnabled(true); - if ((operation & MediaObject.SUPPORT_PANORAMA360) != 0) { - mActivity.invalidateOptionsMenu(); + if (supportCallback.mAllPanorama360) { mShareMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); mShareMenuItem.setTitle( mActivity.getResources().getString(R.string.share_as_photo)); diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java index cacf6fce1..1d110be42 100644 --- a/src/com/android/gallery3d/ui/MenuExecutor.java +++ b/src/com/android/gallery3d/ui/MenuExecutor.java @@ -160,7 +160,6 @@ public class MenuExecutor { boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0; boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0; boolean supportTrim = (supported & MediaObject.SUPPORT_TRIM) != 0; - boolean supportSharePanorama = (supported & MediaObject.SUPPORT_PANORAMA360) != 0; boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0; boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0; boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0; @@ -174,7 +173,8 @@ public class MenuExecutor { setMenuItemVisible(menu, R.id.action_rotate_cw, supportRotate); setMenuItemVisible(menu, R.id.action_crop, supportCrop); setMenuItemVisible(menu, R.id.action_trim, supportTrim); - setMenuItemVisible(menu, R.id.action_share_panorama, supportSharePanorama); + // Hide panorama until call to updateMenuForPanorama corrects it + setMenuItemVisible(menu, R.id.action_share_panorama, false); setMenuItemVisible(menu, R.id.action_share, supportShare); setMenuItemVisible(menu, R.id.action_setas, supportSetAs); setMenuItemVisible(menu, R.id.action_show_on_map, supportShowOnMap); @@ -183,6 +183,16 @@ public class MenuExecutor { setMenuItemVisible(menu, R.id.action_import, supportImport); } + public static void updateMenuForPanorama(Menu menu, boolean shareAsPanorama360, + boolean disablePanorama360Options) { + setMenuItemVisible(menu, R.id.action_share_panorama, shareAsPanorama360); + if (disablePanorama360Options) { + setMenuItemVisible(menu, R.id.action_rotate_ccw, false); + setMenuItemVisible(menu, R.id.action_rotate_cw, false); + setMenuItemVisible(menu, R.id.action_crop, false); + } + } + private static void setMenuItemVisible(Menu menu, int itemId, boolean visible) { MenuItem item = menu.findItem(itemId); if (item != null) item.setVisible(visible); diff --git a/src_pd/com/android/gallery3d/util/LightCycleHelper.java b/src_pd/com/android/gallery3d/util/LightCycleHelper.java index 6ebd9eca2..68c019567 100644 --- a/src_pd/com/android/gallery3d/util/LightCycleHelper.java +++ b/src_pd/com/android/gallery3d/util/LightCycleHelper.java @@ -61,6 +61,8 @@ public class LightCycleHelper { } } + private static final PanoramaMetadata NOT_PANORAMA = new PanoramaMetadata(false, false); + public static void setupCaptureIntent(Context context, Intent it, String outputDir) { /* Do nothing */ } @@ -70,7 +72,7 @@ public class LightCycleHelper { } public static PanoramaMetadata getPanoramaMetadata(Context context, Uri uri) { - return null; + return NOT_PANORAMA; } public static CameraModule createPanoramaModule() { |