In filmstrip, show placeholders for pictures not loaded yet.
Change-Id: I037f1f054da4a3800045d5b89724341ac22272a5
diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java
index ec59997..096e781 100644
--- a/src/com/android/gallery3d/app/PhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java
@@ -210,20 +210,14 @@
for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; ++i) {
mChanges[i + SCREEN_NAIL_MAX] = getVersion(mCurrentIndex + i);
}
- mPhotoView.notifyDataChange(mChanges, mCurrentIndex > 0,
- mCurrentIndex < mSize - 1);
+ mPhotoView.notifyDataChange(mChanges, -mCurrentIndex,
+ mSize - 1 - mCurrentIndex);
}
public void setDataListener(DataListener listener) {
mDataListener = listener;
}
- @Override
- public void setNeedFullImage(boolean enabled) {
- mNeedFullImage = enabled;
- mMainHandler.sendEmptyMessage(MSG_UPDATE_IMAGE_REQUESTS);
- }
-
private void updateScreenNail(long version, Future<ScreenNail> future) {
ImageEntry entry = mImageCache.get(version);
ScreenNail screenNail = future.get();
@@ -307,8 +301,14 @@
return entry == null ? null : entry.screenNail;
}
- public ScreenNail getScreenNail(int offset) {
- return getImage(mCurrentIndex + offset);
+ private MediaItem getItem(int index) {
+ if (index < 0 || index >= mSize || !mIsActive) return null;
+ Utils.assertTrue(index >= mActiveStart && index < mActiveEnd);
+
+ if (index >= mContentStart && index < mContentEnd) {
+ return mData[index % DATA_CACHE_SIZE];
+ }
+ return null;
}
private void updateCurrentIndex(int index) {
@@ -329,14 +329,45 @@
fireDataChange();
}
+ @Override
public void next() {
updateCurrentIndex(mCurrentIndex + 1);
}
+ @Override
public void previous() {
updateCurrentIndex(mCurrentIndex - 1);
}
+ @Override
+ public ScreenNail getScreenNail(int offset) {
+ return getImage(mCurrentIndex + offset);
+ }
+
+ @Override
+ public void getImageSize(int offset, PhotoView.Size size) {
+ MediaItem item = getItem(mCurrentIndex + offset);
+ if (item == null) {
+ size.width = 0;
+ size.height = 0;
+ } else {
+ size.width = item.getWidth();
+ size.height = item.getHeight();
+ }
+ }
+
+ @Override
+ public int getImageRotation(int offset) {
+ MediaItem item = getItem(mCurrentIndex + offset);
+ return (item == null) ? 0 : item.getFullImageRotation();
+ }
+
+ @Override
+ public void setNeedFullImage(boolean enabled) {
+ mNeedFullImage = enabled;
+ mMainHandler.sendEmptyMessage(MSG_UPDATE_IMAGE_REQUESTS);
+ }
+
public ScreenNail getScreenNail() {
return mTileProvider.getScreenNail();
}
@@ -349,11 +380,6 @@
return mTileProvider.getImageWidth();
}
- public int getImageRotation() {
- ImageEntry entry = mImageCache.get(getVersion(mCurrentIndex));
- return entry == null ? 0 : entry.rotation;
- }
-
public int getLevelCount() {
return mTileProvider.getLevelCount();
}
@@ -505,7 +531,7 @@
bitmap = BitmapUtils.rotateBitmap(bitmap,
mItem.getRotation() - mItem.getFullImageRotation(), true);
}
- return new BitmapScreenNail(bitmap, mItem.getFullImageRotation());
+ return new BitmapScreenNail(bitmap);
}
}
diff --git a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
index 59959cf..47f6acb 100644
--- a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
@@ -109,15 +109,6 @@
return false;
}
- public int getImageRotation() {
- return mItem.getRotation();
- }
-
- @Override
- public void setNeedFullImage(boolean enabled) {
- // currently not necessary.
- }
-
private void onDecodeLargeComplete(ImageBundle bundle) {
try {
setScreenNail(bundle.backupImage,
@@ -162,18 +153,43 @@
}
}
- public ScreenNail getScreenNail(int offset) {
- return (offset == 0) ? getScreenNail() : null;
- }
-
+ @Override
public void next() {
throw new UnsupportedOperationException();
}
+ @Override
public void previous() {
throw new UnsupportedOperationException();
}
+ @Override
+ public void getImageSize(int offset, PhotoView.Size size) {
+ if (offset == 0) {
+ size.width = mItem.getWidth();
+ size.height = mItem.getHeight();
+ } else {
+ size.width = 0;
+ size.height = 0;
+ }
+ }
+
+ @Override
+ public int getImageRotation(int offset) {
+ return (offset == 0) ? mItem.getFullImageRotation() : 0;
+ }
+
+ @Override
+ public ScreenNail getScreenNail(int offset) {
+ return (offset == 0) ? getScreenNail() : null;
+ }
+
+ @Override
+ public void setNeedFullImage(boolean enabled) {
+ // currently not necessary.
+ }
+
+
public MediaItem getCurrentMediaItem() {
return mItem;
}
diff --git a/src/com/android/gallery3d/ui/BitmapScreenNail.java b/src/com/android/gallery3d/ui/BitmapScreenNail.java
index 064e1af..7f65405 100644
--- a/src/com/android/gallery3d/ui/BitmapScreenNail.java
+++ b/src/com/android/gallery3d/ui/BitmapScreenNail.java
@@ -29,14 +29,12 @@
private static final String TAG = "BitmapScreenNail";
private final int mWidth;
private final int mHeight;
- private final int mRotation;
private Bitmap mBitmap;
private BitmapTexture mTexture;
- public BitmapScreenNail(Bitmap bitmap, int rotation) {
+ public BitmapScreenNail(Bitmap bitmap) {
mWidth = bitmap.getWidth();
mHeight = bitmap.getHeight();
- mRotation = rotation;
mBitmap = bitmap;
// We create mTexture lazily, so we don't incur the cost if we don't
// actually need it.
@@ -53,11 +51,6 @@
}
@Override
- public int getRotation() {
- return mRotation;
- }
-
- @Override
public void noDraw() {
}
diff --git a/src/com/android/gallery3d/ui/BitmapTileProvider.java b/src/com/android/gallery3d/ui/BitmapTileProvider.java
index 99b64d4..be05b33 100644
--- a/src/com/android/gallery3d/ui/BitmapTileProvider.java
+++ b/src/com/android/gallery3d/ui/BitmapTileProvider.java
@@ -44,7 +44,7 @@
list.add(bitmap);
}
- mScreenNail = new BitmapScreenNail(list.remove(list.size() - 1), 0);
+ mScreenNail = new BitmapScreenNail(list.remove(list.size() - 1));
mMipmaps = list.toArray(new Bitmap[list.size()]);
mConfig = Config.ARGB_8888;
}
diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java
index 306da81..109a5d9 100644
--- a/src/com/android/gallery3d/ui/PhotoView.java
+++ b/src/com/android/gallery3d/ui/PhotoView.java
@@ -38,20 +38,34 @@
public class PhotoView extends GLView {
@SuppressWarnings("unused")
private static final String TAG = "PhotoView";
+ private static final int PLACEHOLDER_COLOR = 0xFF222222;
public static final int INVALID_SIZE = -1;
public static final long INVALID_DATA_VERSION =
MediaObject.INVALID_DATA_VERSION;
- public static interface Model extends TileImageView.Model {
+ public static class Size {
+ public int width;
+ public int height;
+ }
+
+ public interface Model extends TileImageView.Model {
public void next();
public void previous();
- public int getImageRotation();
+
+ // Returns the size for the specified picture. If the size information is
+ // not avaiable, width = height = 0.
+ public void getImageSize(int offset, Size size);
+
+ // Returns the rotation for the specified picture.
+ public int getImageRotation(int offset);
// This amends the getScreenNail() method of TileImageView.Model to get
// ScreenNail at previous (negative offset) or next (positive offset)
// positions. Returns null if the specified ScreenNail is unavailable.
public ScreenNail getScreenNail(int offset);
+
+ // Set this to true if we need the model to provide full images.
public void setNeedFullImage(boolean enabled);
}
@@ -119,6 +133,13 @@
private boolean mCancelExtraScalingPending;
private boolean mFilmMode = false;
+ // [mPrevBound, mNextBound] is the range of index for all pictures in the
+ // model, if we assume the index of current focused picture is 0. So if
+ // there are some previous pictures, mPrevBound < 0, and if there are some
+ // next pictures, mNextBound > 0.
+ private int mPrevBound;
+ private int mNextBound;
+
public PhotoView(GalleryActivity activity) {
mTileView = new TileImageView(activity);
addComponent(mTileView);
@@ -232,8 +253,10 @@
// Data/Image change notifications
////////////////////////////////////////////////////////////////////////////
- public void notifyDataChange(long[] versions, boolean hasPrev,
- boolean hasNext) {
+ public void notifyDataChange(long[] versions, int prevBound, int nextBound) {
+ mPrevBound = prevBound;
+ mNextBound = nextBound;
+
// Check if the data version actually changed.
boolean changed = false;
int N = 2 * SCREEN_NAIL_MAX + 1;
@@ -270,7 +293,7 @@
}
// Move the boxes
- mPositionController.moveBox(mFromIndex, hasPrev, hasNext);
+ mPositionController.moveBox(mFromIndex, mPrevBound < 0, mNextBound > 0);
// Update the ScreenNails.
for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) {
@@ -312,18 +335,14 @@
mTileView.notifyModelInvalidated();
if (CARD_EFFECT) mTileView.setAlpha(1.0f);
- if (mModel == null) {
- mRotation = 0;
- mPositionController.setImageSize(0, 0, 0);
- } else {
- mRotation = mModel.getImageRotation();
- int w = mTileView.mImageWidth;
- int h = mTileView.mImageHeight;
- mPositionController.setImageSize(0,
- getRotated(mRotation, w, h),
- getRotated(mRotation, h, w));
- }
- setScreenNail(mModel == null ? null : mModel.getScreenNail(0));
+ mRotation = mModel.getImageRotation(0);
+ int w = mTileView.mImageWidth;
+ int h = mTileView.mImageHeight;
+ mPositionController.setImageSize(0,
+ getRotated(mRotation, w, h),
+ getRotated(mRotation, h, w));
+
+ setScreenNail(mModel.getScreenNail(0));
updateLoadingState();
}
@@ -447,6 +466,7 @@
private boolean mEnabled;
private int mRotation;
private ScreenNail mScreenNail;
+ private Size mSize = new Size();
public ScreenNailPicture(int index) {
mIndex = index;
@@ -454,12 +474,18 @@
@Override
public void reload() {
- setScreenNail(mModel == null ? null : mModel.getScreenNail(mIndex));
+ setScreenNail(mModel.getScreenNail(mIndex));
}
@Override
public void draw(GLCanvas canvas, Rect r) {
if (mScreenNail == null) {
+ // Draw a placeholder rectange if there will be a picture in
+ // this position.
+ if (mIndex >= mPrevBound && mIndex <= mNextBound) {
+ canvas.fillRect(r.left, r.top, r.width(), r.height(),
+ PLACEHOLDER_COLOR);
+ }
return;
}
if (r.left >= getWidth() || r.right <= 0 ||
@@ -501,12 +527,21 @@
mEnabled = (s != null);
if (mScreenNail == s) return;
mScreenNail = s;
+ mRotation = mModel.getImageRotation(mIndex);
+
+ int w = 0, h = 0;
if (mScreenNail != null) {
- mRotation = mScreenNail.getRotation();
+ w = s.getWidth();
+ h = s.getHeight();
+ } else if (mModel != null) {
+ // If we don't have ScreenNail available, we can still try to
+ // get the size information of it.
+ mModel.getImageSize(mIndex, mSize);
+ w = mSize.width;
+ h = mSize.height;
}
- if (mScreenNail != null) {
- int w = s.getWidth();
- int h = s.getHeight();
+
+ if (w != 0 && h != 0) {
mPositionController.setImageSize(mIndex,
getRotated(mRotation, w, h),
getRotated(mRotation, h, w));
diff --git a/src/com/android/gallery3d/ui/PositionController.java b/src/com/android/gallery3d/ui/PositionController.java
index f087c6b..46f0121 100644
--- a/src/com/android/gallery3d/ui/PositionController.java
+++ b/src/com/android/gallery3d/ui/PositionController.java
@@ -533,7 +533,10 @@
mFilmScroller.fling(p.mCurrentX, 0, velocityX, 0,
Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
int targetX = mFilmScroller.getFinalX();
- ANIM_TIME[ANIM_KIND_FLING] = mFilmScroller.getDuration();
+ // This value doesn't matter because we use mFilmScroller.isFinished()
+ // to decide when to stop. We set this to 0 so it's faster for
+ // Animatable.advanceAnimation() to calculate the progress (always 1).
+ ANIM_TIME[ANIM_KIND_FLING] = 0;
startAnimation(targetX, b.mCurrentY, b.mCurrentScale, ANIM_KIND_FLING);
return true;
}
@@ -1123,8 +1126,8 @@
float scale = Utils.clamp(b.mCurrentScale, scaleMin, scaleMax);
int x = mCurrentX;
if (mFilmMode) {
- if (mHasNext) x = Math.max(x, mViewW / 2);
- if (mHasPrev) x = Math.min(x, mViewW / 2);
+ if (!mHasNext) x = Math.max(x, mViewW / 2);
+ if (!mHasPrev) x = Math.min(x, mViewW / 2);
} else {
calculateStableBound(scale, HORIZONTAL_SLACK);
x = Utils.clamp(x, mBoundLeft, mBoundRight);
diff --git a/src/com/android/gallery3d/ui/ScreenNail.java b/src/com/android/gallery3d/ui/ScreenNail.java
index 25adc77..0a16ab8 100644
--- a/src/com/android/gallery3d/ui/ScreenNail.java
+++ b/src/com/android/gallery3d/ui/ScreenNail.java
@@ -20,7 +20,6 @@
public interface ScreenNail {
public int getWidth();
public int getHeight();
- public int getRotation();
public void draw(GLCanvas canvas, int x, int y, int width, int height);
// We do not need to draw this ScreenNail in this frame.
diff --git a/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java b/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java
index f8442d0..555def8 100644
--- a/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java
+++ b/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java
@@ -77,11 +77,6 @@
}
@Override
- public int getRotation() {
- return 0;
- }
-
- @Override
public void draw(GLCanvas canvas, int x, int y, int width, int height) {
synchronized (this) {
if (!mHasTexture) return;
diff --git a/src/com/android/gallery3d/ui/TileImageViewAdapter.java b/src/com/android/gallery3d/ui/TileImageViewAdapter.java
index 8061657..f4c6e65 100644
--- a/src/com/android/gallery3d/ui/TileImageViewAdapter.java
+++ b/src/com/android/gallery3d/ui/TileImageViewAdapter.java
@@ -41,7 +41,7 @@
public TileImageViewAdapter(
Bitmap bitmap, BitmapRegionDecoder regionDecoder) {
Utils.checkNotNull(bitmap);
- updateScreenNail(new BitmapScreenNail(bitmap, 0), true);
+ updateScreenNail(new BitmapScreenNail(bitmap), true);
mRegionDecoder = regionDecoder;
mImageWidth = regionDecoder.getWidth();
mImageHeight = regionDecoder.getHeight();
@@ -59,7 +59,7 @@
public synchronized void setScreenNail(Bitmap bitmap, int width, int height) {
Utils.checkNotNull(bitmap);
- updateScreenNail(new BitmapScreenNail(bitmap, 0), true);
+ updateScreenNail(new BitmapScreenNail(bitmap), true);
mImageWidth = width;
mImageHeight = height;
mRegionDecoder = null;