summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGeorge Mount <mount@google.com>2012-10-18 14:20:39 -0700
committerGeorge Mount <mount@google.com>2012-10-18 16:32:48 -0700
commit16b3bfbbd2a6447684ac406554f862b29c873751 (patch)
treef2363be751273002eb7716404c601d230ce2cc18 /src
parent79b74e0fd52cd2ba92130c5131474d52170d6f7e (diff)
downloadandroid_packages_apps_Snap-16b3bfbbd2a6447684ac406554f862b29c873751.tar.gz
android_packages_apps_Snap-16b3bfbbd2a6447684ac406554f862b29c873751.tar.bz2
android_packages_apps_Snap-16b3bfbbd2a6447684ac406554f862b29c873751.zip
Remove panorama checks from supported operations.
Bug 7351383 Bug 7349438 Move panorama support checks from getSupportedOperations so that calls to getSupportedOperations are consistent. Panorama checks are moved to only based on callbacks. Change-Id: Id9ff138204df84c6fb0a4c971dcea59f1220aee2
Diffstat (limited to 'src')
-rw-r--r--src/com/android/gallery3d/app/GalleryAppImpl.java1
-rw-r--r--src/com/android/gallery3d/app/PanoramaMetadataSupport.java89
-rw-r--r--src/com/android/gallery3d/app/PhotoPage.java198
-rw-r--r--src/com/android/gallery3d/app/PhotoPageBottomControls.java10
-rw-r--r--src/com/android/gallery3d/data/DataManager.java33
-rw-r--r--src/com/android/gallery3d/data/LocalImage.java66
-rw-r--r--src/com/android/gallery3d/data/MediaObject.java23
-rw-r--r--src/com/android/gallery3d/data/PanoramaMetadataJob.java2
-rw-r--r--src/com/android/gallery3d/data/UriImage.java66
-rw-r--r--src/com/android/gallery3d/ui/ActionModeHandler.java104
-rw-r--r--src/com/android/gallery3d/ui/MenuExecutor.java14
11 files changed, 358 insertions, 248 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);