diff options
author | Paul Rohde <codelogic@google.com> | 2015-01-08 18:47:34 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-01-08 18:47:34 +0000 |
commit | 10ab1989c2475d137a6db36a4d78d8b68fadf96b (patch) | |
tree | 33273d60a9fec5accd1acb5f34a7a9cff03b4ce4 /src/com/android/camera/widget | |
parent | e250f88bc01267f03ae3ae192698b0f07c9e425b (diff) | |
parent | 8ee16b8a323ffa20e6fb1270d498ec445f64defc (diff) | |
download | android_packages_apps_Camera2-10ab1989c2475d137a6db36a4d78d8b68fadf96b.tar.gz android_packages_apps_Camera2-10ab1989c2475d137a6db36a4d78d8b68fadf96b.tar.bz2 android_packages_apps_Camera2-10ab1989c2475d137a6db36a4d78d8b68fadf96b.zip |
Merge "Refactor the filmstrip backing data." into ub-camera-haleakala
Diffstat (limited to 'src/com/android/camera/widget')
-rw-r--r-- | src/com/android/camera/widget/FilmstripLayout.java | 16 | ||||
-rw-r--r-- | src/com/android/camera/widget/FilmstripView.java | 968 |
2 files changed, 527 insertions, 457 deletions
diff --git a/src/com/android/camera/widget/FilmstripLayout.java b/src/com/android/camera/widget/FilmstripLayout.java index 398310050..bbedf240e 100644 --- a/src/com/android/camera/widget/FilmstripLayout.java +++ b/src/com/android/camera/widget/FilmstripLayout.java @@ -59,7 +59,7 @@ public class FilmstripLayout extends FrameLayout implements FilmstripContentPane private FilmstripGestureRecognizer.Listener mFilmstripGestureListener; private final ValueAnimator mFilmstripAnimator = ValueAnimator.ofFloat(null); private int mSwipeTrend; - private MyBackgroundDrawable mBackgroundDrawable; + private FilmstripBackground mBackgroundDrawable; private Handler mHandler; // We use this to record the current translation position instead of using // the real value because we might set the translation before onMeasure() @@ -123,7 +123,7 @@ public class FilmstripLayout extends FrameLayout implements FilmstripContentPane } private void init(Context context) { - mGestureRecognizer = new FilmstripGestureRecognizer(context, new MyGestureListener()); + mGestureRecognizer = new FilmstripGestureRecognizer(context, new OpenFilmstripGesture()); mFilmstripAnimator.setDuration(DEFAULT_DURATION_MS); TimeInterpolator interpolator; if (ApiHelper.isLOrHigher()) { @@ -136,7 +136,7 @@ public class FilmstripLayout extends FrameLayout implements FilmstripContentPane mFilmstripAnimator.addUpdateListener(mFilmstripAnimatorUpdateListener); mFilmstripAnimator.addListener(mFilmstripAnimatorListener); mHandler = new Handler(Looper.getMainLooper()); - mBackgroundDrawable = new MyBackgroundDrawable(); + mBackgroundDrawable = new FilmstripBackground(); mBackgroundDrawable.setCallback(new Drawable.Callback() { @Override public void invalidateDrawable(Drawable drawable) { @@ -203,7 +203,7 @@ public class FilmstripLayout extends FrameLayout implements FilmstripContentPane mListener.onFilmstripShown(); mFilmstripView.zoomAtIndexChanged(); FilmstripController controller = mFilmstripView.getController(); - int currentId = controller.getCurrentId(); + int currentId = controller.getCurrentAdapterIndex(); if (controller.inFilmstrip()) { mListener.onEnterFilmstrip(currentId); } else if (controller.inFullScreen()) { @@ -323,10 +323,10 @@ public class FilmstripLayout extends FrameLayout implements FilmstripContentPane * {@code mFilmstripView} by default and only intercepts scroll gestures * when the {@code mFilmstripView} is not in full-screen. */ - private class MyGestureListener implements FilmstripGestureRecognizer.Listener { + private class OpenFilmstripGesture implements FilmstripGestureRecognizer.Listener { @Override public boolean onScroll(float x, float y, float dx, float dy) { - if (mFilmstripView.getController().getCurrentId() == -1) { + if (mFilmstripView.getController().getCurrentAdapterIndex() == -1) { return true; } if (mFilmstripAnimator.isRunning()) { @@ -464,11 +464,11 @@ public class FilmstripLayout extends FrameLayout implements FilmstripContentPane } } - private class MyBackgroundDrawable extends Drawable { + private class FilmstripBackground extends Drawable { private Paint mPaint; private int mOffset; - public MyBackgroundDrawable() { + public FilmstripBackground() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(getResources().getColor(R.color.filmstrip_background)); diff --git a/src/com/android/camera/widget/FilmstripView.java b/src/com/android/camera/widget/FilmstripView.java index b2529b56d..c213afbec 100644 --- a/src/com/android/camera/widget/FilmstripView.java +++ b/src/com/android/camera/widget/FilmstripView.java @@ -21,7 +21,6 @@ import android.animation.AnimatorSet; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.TargetApi; -import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Point; @@ -43,11 +42,11 @@ import android.view.animation.DecelerateInterpolator; import android.widget.Scroller; import com.android.camera.CameraActivity; -import com.android.camera.data.LocalData.ActionCallback; +import com.android.camera.data.FilmstripItem; +import com.android.camera.data.FilmstripItem.VideoClickedCallback; import com.android.camera.debug.Log; -import com.android.camera.filmstrip.DataAdapter; import com.android.camera.filmstrip.FilmstripController; -import com.android.camera.filmstrip.ImageData; +import com.android.camera.filmstrip.FilmstripDataAdapter; import com.android.camera.ui.FilmstripGestureRecognizer; import com.android.camera.ui.ZoomView; import com.android.camera.util.ApiHelper; @@ -63,15 +62,15 @@ public class FilmstripView extends ViewGroup { /** * An action callback to be used for actions on the local media data items. */ - public static class ActionCallbackImpl implements ActionCallback { - private final WeakReference<Activity> mActivity; + public static class PlayVideoIntent implements VideoClickedCallback { + private final WeakReference<CameraActivity> mActivity; /** * The given activity is used to start intents. It is wrapped in a weak * reference to prevent leaks. */ - public ActionCallbackImpl(Activity activity) { - mActivity = new WeakReference<Activity>(activity); + public PlayVideoIntent(CameraActivity activity) { + mActivity = new WeakReference<CameraActivity>(activity); } /** @@ -79,7 +78,7 @@ public class FilmstripView extends ViewGroup { */ @Override public void playVideo(Uri uri, String title) { - Activity activity = mActivity.get(); + CameraActivity activity = mActivity.get(); if (activity != null) { CameraUtil.playVideo(activity, uri, title); } @@ -90,6 +89,7 @@ public class FilmstripView extends ViewGroup { private static final Log.Tag TAG = new Log.Tag("FilmstripView"); private static final int BUFFER_SIZE = 5; + private static final int BUFFER_CENTER = (BUFFER_SIZE - 1) / 2; private static final int GEOMETRY_ADJUST_TIME_MS = 400; private static final int SNAP_IN_CENTER_TIME_MS = 600; private static final float FLING_COASTING_DURATION_S = 0.05f; @@ -118,18 +118,17 @@ public class FilmstripView extends ViewGroup { private static final float MOUSE_SCROLL_FACTOR = 128f; private CameraActivity mActivity; - private ActionCallback mActionCallback; + private VideoClickedCallback mVideoClickedCallback; private FilmstripGestureRecognizer mGestureRecognizer; private FilmstripGestureRecognizer.Listener mGestureListener; - private DataAdapter mDataAdapter; + private FilmstripDataAdapter mDataAdapter; private int mViewGapInPixel; private final Rect mDrawArea = new Rect(); - private final int mCurrentItem = (BUFFER_SIZE - 1) / 2; private float mScale; - private MyController mController; + private FilmstripControllerImpl mController; private int mCenterX = -1; - private final ViewItem[] mViewItem = new ViewItem[BUFFER_SIZE]; + private final ViewItem[] mViewItems = new ViewItem[BUFFER_SIZE]; private FilmstripController.FilmstripListener mListener; private ZoomView mZoomView = null; @@ -141,44 +140,46 @@ public class FilmstripView extends ViewGroup { // This is true if and only if the user is scrolling, private boolean mIsUserScrolling; - private int mDataIdOnUserScrolling; + private int mAdapterIndexUserIsScrollingOver; private float mOverScaleFactor = 1f; private boolean mFullScreenUIHidden = false; - private final SparseArray<Queue<View>> recycledViews = new SparseArray<Queue<View>>(); + private final SparseArray<Queue<View>> recycledViews = new SparseArray<>(); /** * A helper class to tract and calculate the view coordination. */ - private class ViewItem { - private int mDataId; + private static class ViewItem { + private int mIndex; /** The position of the left of the view in the whole filmstrip. */ private int mLeftPosition; private final View mView; - private final ImageData mData; + private final FilmstripItem mData; private final RectF mViewArea; private boolean mMaximumBitmapRequested; private ValueAnimator mTranslationXAnimator; private ValueAnimator mTranslationYAnimator; private ValueAnimator mAlphaAnimator; + private final FilmstripView mFilmstrip; /** * Constructor. * - * @param id The id of the data from - * {@link com.android.camera.filmstrip.DataAdapter}. + * @param index The index of the data from + * {@link com.android.camera.filmstrip.FilmstripDataAdapter}. * @param v The {@code View} representing the data. */ - public ViewItem(int id, View v, ImageData data) { + public ViewItem(int index, View v, FilmstripItem data, FilmstripView filmstrip) { v.setPivotX(0f); v.setPivotY(0f); - mDataId = id; + mIndex = index; mData = data; mView = v; mMaximumBitmapRequested = false; mLeftPosition = -1; mViewArea = new RectF(); + mFilmstrip = filmstrip; } public boolean isMaximumBitmapRequested() { @@ -190,19 +191,19 @@ public class FilmstripView extends ViewGroup { } /** - * Returns the data id from - * {@link com.android.camera.filmstrip.DataAdapter}. + * Returns the index from + * {@link com.android.camera.filmstrip.FilmstripDataAdapter}. */ - public int getId() { - return mDataId; + public int getAdapterIndex() { + return mIndex; } /** - * Sets the data id from - * {@link com.android.camera.filmstrip.DataAdapter}. + * Sets the index used in the + * {@link com.android.camera.filmstrip.FilmstripDataAdapter}. */ - public void setId(int id) { - mDataId = id; + public void setIndex(int index) { + mIndex = index; } /** Sets the left position of the view in the whole filmstrip. */ @@ -217,22 +218,22 @@ public class FilmstripView extends ViewGroup { /** Returns the translation of Y regarding the view scale. */ public float getTranslationY() { - return mView.getTranslationY() / mScale; + return mView.getTranslationY() / mFilmstrip.mScale; } /** Returns the translation of X regarding the view scale. */ public float getTranslationX() { - return mView.getTranslationX() / mScale; + return mView.getTranslationX() / mFilmstrip.mScale; } /** Sets the translation of Y regarding the view scale. */ public void setTranslationY(float transY) { - mView.setTranslationY(transY * mScale); + mView.setTranslationY(transY * mFilmstrip.mScale); } /** Sets the translation of X regarding the view scale. */ public void setTranslationX(float transX) { - mView.setTranslationX(transX * mScale); + mView.setTranslationX(transX * mFilmstrip.mScale); } /** Forwarding of {@link android.view.View#setAlpha(float)}. */ @@ -272,7 +273,7 @@ public class FilmstripView extends ViewGroup { // translation X because the translation X of the view is // touched in onLayout(). See the documentation of // animateTranslationX(). - invalidate(); + mFilmstrip.invalidate(); } }); } @@ -337,7 +338,7 @@ public class FilmstripView extends ViewGroup { /** Adjusts the translation of X regarding the view scale. */ public void translateXScaledBy(float transX) { - setTranslationX(getTranslationX() + transX * mScale); + setTranslationX(getTranslationX() + transX * mFilmstrip.mScale); } /** @@ -362,20 +363,19 @@ public class FilmstripView extends ViewGroup { } /** - * Notifies the {@link com.android.camera.filmstrip.DataAdapter} to + * Notifies the {@link com.android.camera.filmstrip.FilmstripDataAdapter} to * resize the view. */ - public void resizeView(Context context, int w, int h) { - mDataAdapter.resizeView(context, mDataId, mView, w, h); + public void resizeView(int w, int h) { + mFilmstrip.mDataAdapter.resizeView(mIndex, mView, w, h); } /** * Adds the view of the data to the view hierarchy if necessary. */ public void addViewToHierarchy() { - if (indexOfChild(mView) < 0) { - mData.prepare(); - addView(mView); + if (mFilmstrip.indexOfChild(mView) < 0) { + mFilmstrip.addView(mView); } setVisibility(View.VISIBLE); @@ -392,10 +392,10 @@ public class FilmstripView extends ViewGroup { * regardless of the view type. */ public void removeViewFromHierarchy(boolean force) { - if (force || mData.getViewType() != ImageData.VIEW_TYPE_STICKY) { - removeView(mView); + if (force || !mData.getAttributes().isSticky()) { + mFilmstrip.removeView(mView); mData.recycle(mView); - recycleView(mView, mDataId); + mFilmstrip.recycleView(mView, mIndex); } else { setVisibility(View.INVISIBLE); } @@ -406,7 +406,7 @@ public class FilmstripView extends ViewGroup { * {@link #bringChildToFront(android.view.View)} */ public void bringViewToFront() { - bringChildToFront(mView); + mFilmstrip.bringChildToFront(mView); } /** @@ -512,7 +512,7 @@ public class FilmstripView extends ViewGroup { // translation X because the translation X of the view is // touched in onLayout(). See the documentation of // animateTranslationX(). - invalidate(); + mFilmstrip.invalidate(); } }); } @@ -586,7 +586,7 @@ public class FilmstripView extends ViewGroup { @Override public String toString() { - return "DataID = " + mDataId + "\n\t left = " + mLeftPosition + return "AdapterIndex = " + mIndex + "\n\t left = " + mLeftPosition + "\n\t viewArea = " + mViewArea + "\n\t centerX = " + getCenterX() + "\n\t view MeasuredSize = " @@ -617,16 +617,16 @@ public class FilmstripView extends ViewGroup { private void init(CameraActivity cameraActivity) { setWillNotDraw(false); mActivity = cameraActivity; - mActionCallback = new ActionCallbackImpl(mActivity); + mVideoClickedCallback = new PlayVideoIntent(mActivity); mScale = 1.0f; - mDataIdOnUserScrolling = 0; - mController = new MyController(cameraActivity); + mAdapterIndexUserIsScrollingOver = 0; + mController = new FilmstripControllerImpl(); mViewAnimInterpolator = new DecelerateInterpolator(); mZoomView = new ZoomView(cameraActivity); mZoomView.setVisibility(GONE); addView(mZoomView); - mGestureListener = new MyGestureReceiver(); + mGestureListener = new FilmstripGestures(); mGestureRecognizer = new FilmstripGestureRecognizer(cameraActivity, mGestureListener); mSlop = (int) getContext().getResources().getDimension(R.dimen.pie_touch_slop); @@ -671,7 +671,7 @@ public class FilmstripView extends ViewGroup { case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { // Prevent the view group itself from being selected. // Instead, select the item in the center - final ViewItem currentItem = mViewItem[mCurrentItem]; + final ViewItem currentItem = mViewItems[BUFFER_CENTER]; currentItem.getView().performAccessibilityAction(action, args); return true; } @@ -682,7 +682,7 @@ public class FilmstripView extends ViewGroup { }); } - private void recycleView(View view, int dataId) { + private void recycleView(View view, int index) { final int viewType = (Integer) view.getTag(R.id.mediadata_tag_viewtype); if (viewType > 0) { Queue<View> recycledViewsForType = recycledViews.get(viewType); @@ -694,17 +694,17 @@ public class FilmstripView extends ViewGroup { } } - private View getRecycledView(int dataId) { - final int viewType = mDataAdapter.getItemViewType(dataId); + private View getRecycledView(int index) { + final int viewType = mDataAdapter.getItemViewType(index); Queue<View> recycledViewsForType = recycledViews.get(viewType); - View result = null; + View view = null; if (recycledViewsForType != null) { - result = recycledViewsForType.poll(); + view = recycledViewsForType.poll(); } - if (result != null) { - result.setVisibility(View.GONE); + if (view != null) { + view.setVisibility(View.GONE); } - return result; + return view; } /** @@ -720,7 +720,7 @@ public class FilmstripView extends ViewGroup { * Returns the draw area width of the current item. */ public int getCurrentItemLeft() { - return mViewItem[mCurrentItem].getDrawAreaLeft(); + return mViewItems[BUFFER_CENTER].getDrawAreaLeft(); } private void setListener(FilmstripController.FilmstripListener l) { @@ -735,24 +735,24 @@ public class FilmstripView extends ViewGroup { * Called after current item or zoom level has changed. */ public void zoomAtIndexChanged() { - if (mViewItem[mCurrentItem] == null) { + if (mViewItems[BUFFER_CENTER] == null) { return; } - int id = mViewItem[mCurrentItem].getId(); - mListener.onZoomAtIndexChanged(id, mScale); + int index = mViewItems[BUFFER_CENTER].getAdapterIndex(); + mListener.onZoomAtIndexChanged(index, mScale); } /** * Checks if the data is at the center. * - * @param id The id of the data to check. + * @param index The index of the item in the data adapter to check. * @return {@code True} if the data is currently at the center. */ - private boolean isDataAtCenter(int id) { - if (mViewItem[mCurrentItem] == null) { + private boolean isItemAtIndexCentered(int index) { + if (mViewItems[BUFFER_CENTER] == null) { return false; } - if (mViewItem[mCurrentItem].getId() == id + if (mViewItems[BUFFER_CENTER].getAdapterIndex() == index && isCurrentItemCentered()) { return true; } @@ -760,15 +760,19 @@ public class FilmstripView extends ViewGroup { } private void measureViewItem(ViewItem item, int boundWidth, int boundHeight) { - int id = item.getId(); - ImageData imageData = mDataAdapter.getImageData(id); + int index = item.getAdapterIndex(); + FilmstripItem imageData = mDataAdapter.getFilmstripItemAt(index); if (imageData == null) { Log.e(TAG, "trying to measure a null item"); return; } - Point dim = CameraUtil.resizeToFill(imageData.getWidth(), imageData.getHeight(), - imageData.getRotation(), boundWidth, boundHeight); + Point dim = CameraUtil.resizeToFill( + imageData.getData().getDimensions().getWidth(), + imageData.getData().getDimensions().getHeight(), + imageData.getData().getOrientation(), + boundWidth, + boundHeight); item.measure(MeasureSpec.makeMeasureSpec(dim.x, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dim.y, MeasureSpec.EXACTLY)); @@ -785,7 +789,7 @@ public class FilmstripView extends ViewGroup { return; } - for (ViewItem item : mViewItem) { + for (ViewItem item : mViewItems) { if (item != null) { measureViewItem(item, boundWidth, boundHeight); } @@ -796,12 +800,11 @@ public class FilmstripView extends ViewGroup { MeasureSpec.makeMeasureSpec(heightMeasureSpec, MeasureSpec.EXACTLY)); } - private int findTheNearestView(int pointX) { - + private int findTheNearestView(int viewX) { int nearest = 0; // Find the first non-null ViewItem. while (nearest < BUFFER_SIZE - && (mViewItem[nearest] == null || mViewItem[nearest].getLeftPosition() == -1)) { + && (mViewItems[nearest] == null || mViewItems[nearest].getLeftPosition() == -1)) { nearest++; } // No existing available ViewItem @@ -809,32 +812,32 @@ public class FilmstripView extends ViewGroup { return -1; } - int min = Math.abs(pointX - mViewItem[nearest].getCenterX()); + int min = Math.abs(viewX - mViewItems[nearest].getCenterX()); - for (int itemID = nearest + 1; itemID < BUFFER_SIZE && mViewItem[itemID] != null; itemID++) { + for (int i = nearest + 1; i < BUFFER_SIZE && mViewItems[i] != null; i++) { // Not measured yet. - if (mViewItem[itemID].getLeftPosition() == -1) { + if (mViewItems[i].getLeftPosition() == -1) { continue; } - int c = mViewItem[itemID].getCenterX(); - int dist = Math.abs(pointX - c); + int centerX = mViewItems[i].getCenterX(); + int dist = Math.abs(viewX - centerX); if (dist < min) { min = dist; - nearest = itemID; + nearest = i; } } return nearest; } - private ViewItem buildItemFromData(int dataID) { + private ViewItem buildViewItemAt(int index) { if (mActivity.isDestroyed()) { // Loading item data is call from multiple AsyncTasks and the - // activity may be finished when buildItemFromData is called. + // activity may be finished when buildViewItemAt is called. Log.d(TAG, "Activity destroyed, don't load data"); return null; } - ImageData data = mDataAdapter.getImageData(dataID); + FilmstripItem data = mDataAdapter.getFilmstripItemAt(index); if (data == null) { return null; } @@ -847,47 +850,53 @@ public class FilmstripView extends ViewGroup { Log.v(TAG, "suggesting item bounds: " + width + "x" + height); mDataAdapter.suggestViewSizeBound(width, height); - data.prepare(); - View recycled = getRecycledView(dataID); - View v = mDataAdapter.getView(mActivity.getAndroidContext(), recycled, dataID, - mActionCallback); + View recycled = getRecycledView(index); + View v = mDataAdapter.getView(recycled, index, + mVideoClickedCallback); if (v == null) { return null; } - ViewItem item = new ViewItem(dataID, v, data); + ViewItem item = new ViewItem(index, v, data, this); item.addViewToHierarchy(); return item; } - private void checkItemAtMaxSize() { - ViewItem item = mViewItem[mCurrentItem]; - if (item.isMaximumBitmapRequested()) { + private void ensureItemAtMaxSize(int bufferIndex) { + ViewItem item = mViewItems[bufferIndex]; + if (item == null || item.isMaximumBitmapRequested()) { return; - }; + } item.setMaximumBitmapRequested(); // Request full size bitmap, or max that DataAdapter will create. - int id = item.getId(); - int h = mDataAdapter.getImageData(id).getHeight(); - int w = mDataAdapter.getImageData(id).getWidth(); - item.resizeView(mActivity, w, h); + int index = item.getAdapterIndex(); + int h = mDataAdapter.getFilmstripItemAt(index).getData().getDimensions().getHeight(); + int w = mDataAdapter.getFilmstripItemAt(index).getData().getDimensions().getWidth(); + item.resizeView(w, h); } - private void removeItem(int itemID) { - if (itemID >= mViewItem.length || mViewItem[itemID] == null) { + private void ensureBufferItemsAtMaxSize() { + for(int i = 0; i < BUFFER_SIZE; i++) { + ensureItemAtMaxSize(i); + } + } + + private void removeItem(int bufferIndex) { + if (bufferIndex >= mViewItems.length || mViewItems[bufferIndex] == null) { return; } - ImageData data = mDataAdapter.getImageData(mViewItem[itemID].getId()); + FilmstripItem data = mDataAdapter.getFilmstripItemAt( + mViewItems[bufferIndex].getAdapterIndex()); if (data == null) { Log.e(TAG, "trying to remove a null item"); return; } - mViewItem[itemID].removeViewFromHierarchy(false); - mViewItem[itemID] = null; + mViewItems[bufferIndex].removeViewFromHierarchy(false); + mViewItems[bufferIndex] = null; } /** * We try to keep the one closest to the center of the screen at position - * mCurrentItem. + * BUFFER_CENTER. */ private void stepIfNeeded() { if (!inFilmstrip() && !inFullScreen()) { @@ -895,45 +904,54 @@ public class FilmstripView extends ViewGroup { // not in transition. return; } - final int nearest = findTheNearestView(mCenterX); - // no change made. - if (nearest == -1 || nearest == mCurrentItem) { + final int nearestBufferIndex = findTheNearestView(mCenterX); + // if the nearest view is the current view, or there is no nearest + // view, then we do not need to adjust the view buffers. + if (nearestBufferIndex == -1 || nearestBufferIndex == BUFFER_CENTER) { return; } - int prevDataId = (mViewItem[mCurrentItem] == null ? -1 : mViewItem[mCurrentItem].getId()); - final int adjust = nearest - mCurrentItem; + int prevIndex = (mViewItems[BUFFER_CENTER] == null ? -1 : + mViewItems[BUFFER_CENTER].getAdapterIndex()); + final int adjust = nearestBufferIndex - BUFFER_CENTER; if (adjust > 0) { + // Remove from beginning of the buffer. for (int k = 0; k < adjust; k++) { removeItem(k); } + // Shift items inside the buffer for (int k = 0; k + adjust < BUFFER_SIZE; k++) { - mViewItem[k] = mViewItem[k + adjust]; + mViewItems[k] = mViewItems[k + adjust]; } + // Fill the end with new items. for (int k = BUFFER_SIZE - adjust; k < BUFFER_SIZE; k++) { - mViewItem[k] = null; - if (mViewItem[k - 1] != null) { - mViewItem[k] = buildItemFromData(mViewItem[k - 1].getId() + 1); + mViewItems[k] = null; + if (mViewItems[k - 1] != null) { + mViewItems[k] = buildViewItemAt(mViewItems[k - 1].getAdapterIndex() + 1); } } adjustChildZOrder(); } else { + // Remove from the end of the buffer for (int k = BUFFER_SIZE - 1; k >= BUFFER_SIZE + adjust; k--) { removeItem(k); } + // Shift items inside the buffer for (int k = BUFFER_SIZE - 1; k + adjust >= 0; k--) { - mViewItem[k] = mViewItem[k + adjust]; + mViewItems[k] = mViewItems[k + adjust]; } + // Fill the beginning with new items. for (int k = -1 - adjust; k >= 0; k--) { - mViewItem[k] = null; - if (mViewItem[k + 1] != null) { - mViewItem[k] = buildItemFromData(mViewItem[k + 1].getId() - 1); + mViewItems[k] = null; + if (mViewItems[k + 1] != null) { + mViewItems[k] = buildViewItemAt(mViewItems[k + 1].getAdapterIndex() - 1); } } } invalidate(); if (mListener != null) { - mListener.onDataFocusChanged(prevDataId, mViewItem[mCurrentItem].getId()); - final int firstVisible = mViewItem[mCurrentItem].getId() - 2; + mListener.onDataFocusChanged(prevIndex, mViewItems[BUFFER_CENTER] + .getAdapterIndex()); + final int firstVisible = mViewItems[BUFFER_CENTER].getAdapterIndex() - 2; final int visibleItemCount = firstVisible + BUFFER_SIZE; final int totalItemCount = mDataAdapter.getTotalNumber(); mListener.onScroll(firstVisible, visibleItemCount, totalItemCount); @@ -948,45 +966,46 @@ public class FilmstripView extends ViewGroup { * @return Whether clamp happened. */ private boolean clampCenterX() { - ViewItem curr = mViewItem[mCurrentItem]; - if (curr == null) { + ViewItem currentItem = mViewItems[BUFFER_CENTER]; + if (currentItem == null) { return false; } boolean stopScroll = false; - if (curr.getId() == 1 && mCenterX < curr.getCenterX() && mDataIdOnUserScrolling > 1 && - mDataAdapter.getImageData(0).getViewType() == ImageData.VIEW_TYPE_STICKY && + if (currentItem.getAdapterIndex() == 1 && mCenterX < currentItem.getCenterX() + && mAdapterIndexUserIsScrollingOver > 1 && + mDataAdapter.getFilmstripItemAt(0).getAttributes().isSticky() && mController.isScrolling()) { stopScroll = true; } else { - if (curr.getId() == 0 && mCenterX < curr.getCenterX()) { + if (currentItem.getAdapterIndex() == 0 && mCenterX < currentItem.getCenterX()) { // Stop at the first ViewItem. stopScroll = true; } } - if (curr.getId() == mDataAdapter.getTotalNumber() - 1 - && mCenterX > curr.getCenterX()) { + if (currentItem.getAdapterIndex() == mDataAdapter.getTotalNumber() - 1 + && mCenterX > currentItem.getCenterX()) { // Stop at the end. stopScroll = true; } if (stopScroll) { - mCenterX = curr.getCenterX(); + mCenterX = currentItem.getCenterX(); } return stopScroll; } /** - * Reorders the child views to be consistent with their data ID. This method + * Reorders the child views to be consistent with their index. This method * should be called after adding/removing views. */ private void adjustChildZOrder() { for (int i = BUFFER_SIZE - 1; i >= 0; i--) { - if (mViewItem[i] == null) { + if (mViewItems[i] == null) { continue; } - mViewItem[i].bringViewToFront(); + mViewItems[i].bringViewToFront(); } // ZoomView is a special case to always be in the front. In L set to // max elevation to make sure ZoomView is above other elevated views. @@ -1002,36 +1021,39 @@ public class FilmstripView extends ViewGroup { } /** - * Returns the ID of the current item, or -1 if there is no data. + * Returns the index of the current item, or -1 if there is no data. */ - private int getCurrentId() { - ViewItem current = mViewItem[mCurrentItem]; + private int getCurrentItemAdapterIndex() { + ViewItem current = mViewItems[BUFFER_CENTER]; if (current == null) { return -1; } - return current.getId(); + return current.getAdapterIndex(); } /** * Keep the current item in the center. This functions does not check if the * current item is null. */ - private void snapInCenter() { - final ViewItem currItem = mViewItem[mCurrentItem]; + private void scrollCurrentItemToCenter() { + final ViewItem currItem = mViewItems[BUFFER_CENTER]; if (currItem == null) { return; } final int currentViewCenter = currItem.getCenterX(); if (mController.isScrolling() || mIsUserScrolling || isCurrentItemCentered()) { + Log.e(TAG, "[fling] = mController.isScrolling() " + mController.isScrolling()); return; } int snapInTime = (int) (SNAP_IN_CENTER_TIME_MS * ((float) Math.abs(mCenterX - currentViewCenter)) / mDrawArea.width()); + + Log.e(TAG, "[fling] Scroll to center."); mController.scrollToPosition(currentViewCenter, - snapInTime, false); + snapInTime, false); if (isViewTypeSticky(currItem) && !mController.isScaling() && mScale != FULL_SCREEN_SCALE) { // Now going to full screen camera mController.goToFullScreen(); @@ -1044,24 +1066,24 @@ public class FilmstripView extends ViewGroup { * which occupies the whole screen. The other left ones are put on the left * side in full scales. Does nothing if there's no next item. * - * @param currItem The item ID of the current one to be translated. + * @param index The index of the current one to be translated. * @param drawAreaWidth The width of the current draw area. * @param scaleFraction A {@code float} between 0 and 1. 0 if the current * scale is {@code FILM_STRIP_SCALE}. 1 if the current scale is * {@code FULL_SCREEN_SCALE}. */ private void translateLeftViewItem( - int currItem, int drawAreaWidth, float scaleFraction) { - if (currItem < 0 || currItem > BUFFER_SIZE - 1) { - Log.e(TAG, "currItem id out of bound."); + int index, int drawAreaWidth, float scaleFraction) { + if (index < 0 || index > BUFFER_SIZE - 1) { + Log.e(TAG, "index out of bound."); return; } - final ViewItem curr = mViewItem[currItem]; - final ViewItem next = mViewItem[currItem + 1]; + final ViewItem curr = mViewItems[index]; + final ViewItem next = mViewItems[index + 1]; if (curr == null || next == null) { Log.e(TAG, "Invalid view item (curr or next == null). curr = " - + currItem); + + index); return; } @@ -1075,7 +1097,8 @@ public class FilmstripView extends ViewGroup { curr.setVisibility(VISIBLE); if (inFullScreen()) { - curr.setTranslationX(translate * (mCenterX - currCenterX) / (nextCenterX - currCenterX)); + curr.setTranslationX(translate * (mCenterX - currCenterX) / + (nextCenterX - currCenterX)); } else { curr.setTranslationX(translate); } @@ -1085,46 +1108,46 @@ public class FilmstripView extends ViewGroup { * Fade out the {@link ViewItem} on the right of the current one in * full-screen layout. Does nothing if there's no previous item. * - * @param currItemId The ID of the item to fade. + * @param bufferIndex The index of the item in the buffer to fade. */ - private void fadeAndScaleRightViewItem(int currItemId) { - if (currItemId < 1 || currItemId > BUFFER_SIZE) { - Log.e(TAG, "currItem id out of bound."); + private void fadeAndScaleRightViewItem(int bufferIndex) { + if (bufferIndex < 1 || bufferIndex > BUFFER_SIZE) { + Log.e(TAG, "index id out of bound."); return; } - final ViewItem currItem = mViewItem[currItemId]; - final ViewItem prevItem = mViewItem[currItemId - 1]; - if (currItem == null || prevItem == null) { + final ViewItem item = mViewItems[bufferIndex]; + final ViewItem previousItem = mViewItems[bufferIndex - 1]; + if (item == null || previousItem == null) { Log.e(TAG, "Invalid view item (curr or prev == null). curr = " - + currItemId); + + bufferIndex); return; } - if (currItemId > mCurrentItem + 1) { - // Every item not right next to the mCurrentItem is invisible. - currItem.setVisibility(INVISIBLE); + if (bufferIndex > BUFFER_CENTER + 1) { + // Every item not right next to the BUFFER_CENTER is invisible. + item.setVisibility(INVISIBLE); return; } - final int prevCenterX = prevItem.getCenterX(); + final int prevCenterX = previousItem.getCenterX(); if (mCenterX <= prevCenterX) { // Shortcut. If the position is at the center of the previous one, // set to invisible too. - currItem.setVisibility(INVISIBLE); + item.setVisibility(INVISIBLE); return; } - final int currCenterX = currItem.getCenterX(); + final int currCenterX = item.getCenterX(); final float fadeDownFraction = ((float) mCenterX - prevCenterX) / (currCenterX - prevCenterX); - currItem.layoutWithTranslationX(mDrawArea, currCenterX, - FILM_STRIP_SCALE + (1f - FILM_STRIP_SCALE) * fadeDownFraction); - currItem.setAlpha(fadeDownFraction); - currItem.setTranslationX(0); - currItem.setVisibility(VISIBLE); + item.layoutWithTranslationX(mDrawArea, currCenterX, + FILM_STRIP_SCALE + (1f - FILM_STRIP_SCALE) * fadeDownFraction); + item.setAlpha(fadeDownFraction); + item.setTranslationX(0); + item.setVisibility(VISIBLE); } private void layoutViewItems(boolean layoutChanged) { - if (mViewItem[mCurrentItem] == null || + if (mViewItems[BUFFER_CENTER] == null || mDrawArea.width() == 0 || mDrawArea.height() == 0) { return; @@ -1133,8 +1156,8 @@ public class FilmstripView extends ViewGroup { // If the layout changed, we need to adjust the current position so // that if an item is centered before the change, it's still centered. if (layoutChanged) { - mViewItem[mCurrentItem].setLeftPosition( - mCenterX - mViewItem[mCurrentItem].getMeasuredWidth() / 2); + mViewItems[BUFFER_CENTER].setLeftPosition( + mCenterX - mViewItems[BUFFER_CENTER].getMeasuredWidth() / 2); } if (inZoomView()) { @@ -1153,26 +1176,26 @@ public class FilmstripView extends ViewGroup { // first. // Left items. - for (int itemID = mCurrentItem - 1; itemID >= 0; itemID--) { - final ViewItem curr = mViewItem[itemID]; + for (int i = BUFFER_CENTER - 1; i >= 0; i--) { + final ViewItem curr = mViewItems[i]; if (curr == null) { break; } // First, layout relatively to the next one. - final int currLeft = mViewItem[itemID + 1].getLeftPosition() + final int currLeft = mViewItems[i + 1].getLeftPosition() - curr.getMeasuredWidth() - mViewGapInPixel; curr.setLeftPosition(currLeft); } // Right items. - for (int itemID = mCurrentItem + 1; itemID < BUFFER_SIZE; itemID++) { - final ViewItem curr = mViewItem[itemID]; + for (int i = BUFFER_CENTER + 1; i < BUFFER_SIZE; i++) { + final ViewItem curr = mViewItems[i]; if (curr == null) { break; } // First, layout relatively to the previous one. - final ViewItem prev = mViewItem[itemID - 1]; + final ViewItem prev = mViewItems[i - 1]; final int currLeft = prev.getLeftPosition() + prev.getMeasuredWidth() + mViewGapInPixel; @@ -1182,8 +1205,8 @@ public class FilmstripView extends ViewGroup { // Special case for the one immediately on the right of the camera // preview. boolean immediateRight = - (mViewItem[mCurrentItem].getId() == 1 && - mDataAdapter.getImageData(0).getViewType() == ImageData.VIEW_TYPE_STICKY); + (mViewItems[BUFFER_CENTER].getAdapterIndex() == 1 && + mDataAdapter.getFilmstripItemAt(0).getAttributes().isSticky()); // Layout the current ViewItem first. if (immediateRight) { @@ -1191,37 +1214,37 @@ public class FilmstripView extends ViewGroup { // fading. The implementation in Gallery does not push the first // photo to the bottom of the camera preview. Simply place the // photo on the right of the preview. - final ViewItem currItem = mViewItem[mCurrentItem]; + final ViewItem currItem = mViewItems[BUFFER_CENTER]; currItem.layoutWithTranslationX(mDrawArea, mCenterX, mScale); currItem.setTranslationX(0f); currItem.setAlpha(1f); } else if (scaleFraction == 1f) { - final ViewItem currItem = mViewItem[mCurrentItem]; + final ViewItem currItem = mViewItems[BUFFER_CENTER]; final int currCenterX = currItem.getCenterX(); if (mCenterX < currCenterX) { // In full-screen and mCenterX is on the left of the center, // we draw the current one to "fade down". - fadeAndScaleRightViewItem(mCurrentItem); + fadeAndScaleRightViewItem(BUFFER_CENTER); } else if (mCenterX > currCenterX) { // In full-screen and mCenterX is on the right of the center, // we draw the current one translated. - translateLeftViewItem(mCurrentItem, fullScreenWidth, scaleFraction); + translateLeftViewItem(BUFFER_CENTER, fullScreenWidth, scaleFraction); } else { currItem.layoutWithTranslationX(mDrawArea, mCenterX, mScale); currItem.setTranslationX(0f); currItem.setAlpha(1f); } } else { - final ViewItem currItem = mViewItem[mCurrentItem]; + final ViewItem currItem = mViewItems[BUFFER_CENTER]; // The normal filmstrip has no translation for the current item. If // it has translation before, gradually set it to zero. currItem.setTranslationX(currItem.getTranslationX() * scaleFraction); currItem.layoutWithTranslationX(mDrawArea, mCenterX, mScale); - if (mViewItem[mCurrentItem - 1] == null) { + if (mViewItems[BUFFER_CENTER - 1] == null) { currItem.setAlpha(1f); } else { final int currCenterX = currItem.getCenterX(); - final int prevCenterX = mViewItem[mCurrentItem - 1].getCenterX(); + final int prevCenterX = mViewItems[BUFFER_CENTER - 1].getCenterX(); final float fadeDownFraction = ((float) mCenterX - prevCenterX) / (currCenterX - prevCenterX); currItem.setAlpha( @@ -1232,23 +1255,23 @@ public class FilmstripView extends ViewGroup { // Layout the rest dependent on the current scale. // Items on the left - for (int itemID = mCurrentItem - 1; itemID >= 0; itemID--) { - final ViewItem curr = mViewItem[itemID]; + for (int i = BUFFER_CENTER - 1; i >= 0; i--) { + final ViewItem curr = mViewItems[i]; if (curr == null) { break; } - translateLeftViewItem(itemID, fullScreenWidth, scaleFraction); + translateLeftViewItem(i, fullScreenWidth, scaleFraction); } // Items on the right - for (int itemID = mCurrentItem + 1; itemID < BUFFER_SIZE; itemID++) { - final ViewItem curr = mViewItem[itemID]; + for (int i = BUFFER_CENTER + 1; i < BUFFER_SIZE; i++) { + final ViewItem curr = mViewItems[i]; if (curr == null) { break; } curr.layoutWithTranslationX(mDrawArea, mCenterX, mScale); - if (curr.getId() == 1 && isViewTypeSticky(curr)) { + if (curr.getAdapterIndex() == 1 && isViewTypeSticky(curr)) { // Special case for the one next to the camera preview. curr.setAlpha(1f); continue; @@ -1256,11 +1279,11 @@ public class FilmstripView extends ViewGroup { if (scaleFraction == 1) { // It's in full-screen mode. - fadeAndScaleRightViewItem(itemID); + fadeAndScaleRightViewItem(i); } else { boolean setToVisible = (curr.getVisibility() == INVISIBLE); - if (itemID == mCurrentItem + 1) { + if (i == BUFFER_CENTER + 1) { curr.setAlpha(1f - scaleFraction); } else { if (scaleFraction == 0f) { @@ -1274,9 +1297,8 @@ public class FilmstripView extends ViewGroup { curr.setVisibility(VISIBLE); } - curr.setTranslationX( - (mViewItem[mCurrentItem].getLeftPosition() - curr.getLeftPosition()) * - scaleFraction); + curr.setTranslationX((mViewItems[BUFFER_CENTER].getLeftPosition() - + curr.getLeftPosition()) * scaleFraction); } } @@ -1287,8 +1309,7 @@ public class FilmstripView extends ViewGroup { if (item == null) { return false; } - return mDataAdapter.getImageData(item.getId()).getViewType() == - ImageData.VIEW_TYPE_STICKY; + return mDataAdapter.getFilmstripItemAt(item.getAdapterIndex()).getAttributes().isSticky(); } @Override @@ -1324,7 +1345,7 @@ public class FilmstripView extends ViewGroup { if (!inZoomView()) { return; } - ViewItem current = mViewItem[mCurrentItem]; + ViewItem current = mViewItems[BUFFER_CENTER]; if (current == null) { return; } @@ -1350,75 +1371,75 @@ public class FilmstripView extends ViewGroup { item.animateAlpha(1f, GEOMETRY_ADJUST_TIME_MS, mViewAnimInterpolator); } - private void animateItemRemoval(int dataID, final ImageData data) { + private void animateItemRemoval(int index) { if (mScale > FULL_SCREEN_SCALE) { resetZoomView(); } - int removedItemId = findItemByDataID(dataID); + int removeAtBufferIndex = findItemInBufferByAdapterIndex(index); - // adjust the data id to be consistent + // adjust the buffer to be consistent for (int i = 0; i < BUFFER_SIZE; i++) { - if (mViewItem[i] == null || mViewItem[i].getId() <= dataID) { + if (mViewItems[i] == null || mViewItems[i].getAdapterIndex() <= index) { continue; } - mViewItem[i].setId(mViewItem[i].getId() - 1); + mViewItems[i].setIndex(mViewItems[i].getAdapterIndex() - 1); } - if (removedItemId == -1) { + if (removeAtBufferIndex == -1) { return; } - final ViewItem removedItem = mViewItem[removedItemId]; + final ViewItem removedItem = mViewItems[removeAtBufferIndex]; final int offsetX = removedItem.getMeasuredWidth() + mViewGapInPixel; - for (int i = removedItemId + 1; i < BUFFER_SIZE; i++) { - if (mViewItem[i] != null) { - mViewItem[i].setLeftPosition(mViewItem[i].getLeftPosition() - offsetX); + for (int i = removeAtBufferIndex + 1; i < BUFFER_SIZE; i++) { + if (mViewItems[i] != null) { + mViewItems[i].setLeftPosition(mViewItems[i].getLeftPosition() - offsetX); } } - if (removedItemId >= mCurrentItem - && mViewItem[removedItemId].getId() < mDataAdapter.getTotalNumber()) { + if (removeAtBufferIndex >= BUFFER_CENTER + && mViewItems[removeAtBufferIndex].getAdapterIndex() < mDataAdapter.getTotalNumber()) { // Fill the removed item by left shift when the current one or // anyone on the right is removed, and there's more data on the // right available. - for (int i = removedItemId; i < BUFFER_SIZE - 1; i++) { - mViewItem[i] = mViewItem[i + 1]; + for (int i = removeAtBufferIndex; i < BUFFER_SIZE - 1; i++) { + mViewItems[i] = mViewItems[i + 1]; } // pull data out from the DataAdapter for the last one. int curr = BUFFER_SIZE - 1; int prev = curr - 1; - if (mViewItem[prev] != null) { - mViewItem[curr] = buildItemFromData(mViewItem[prev].getId() + 1); + if (mViewItems[prev] != null) { + mViewItems[curr] = buildViewItemAt(mViewItems[prev].getAdapterIndex() + 1); } // The animation part. if (inFullScreen()) { - mViewItem[mCurrentItem].setVisibility(VISIBLE); - ViewItem nextItem = mViewItem[mCurrentItem + 1]; + mViewItems[BUFFER_CENTER].setVisibility(VISIBLE); + ViewItem nextItem = mViewItems[BUFFER_CENTER + 1]; if (nextItem != null) { nextItem.setVisibility(INVISIBLE); } } // Translate the views to their original places. - for (int i = removedItemId; i < BUFFER_SIZE; i++) { - if (mViewItem[i] != null) { - mViewItem[i].setTranslationX(offsetX); + for (int i = removeAtBufferIndex; i < BUFFER_SIZE; i++) { + if (mViewItems[i] != null) { + mViewItems[i].setTranslationX(offsetX); } } // The end of the filmstrip might have been changed. // The mCenterX might be out of the bound. - ViewItem currItem = mViewItem[mCurrentItem]; - if(currItem!=null) { - if (currItem.getId() == mDataAdapter.getTotalNumber() - 1 + ViewItem currItem = mViewItems[BUFFER_CENTER]; + if (currItem!=null) { + if (currItem.getAdapterIndex() == mDataAdapter.getTotalNumber() - 1 && mCenterX > currItem.getCenterX()) { int adjustDiff = currItem.getCenterX() - mCenterX; mCenterX = currItem.getCenterX(); for (int i = 0; i < BUFFER_SIZE; i++) { - if (mViewItem[i] != null) { - mViewItem[i].translateXScaledBy(adjustDiff); + if (mViewItems[i] != null) { + mViewItems[i].translateXScaledBy(adjustDiff); } } } @@ -1430,21 +1451,22 @@ public class FilmstripView extends ViewGroup { // fill the removed place by right shift mCenterX -= offsetX; - for (int i = removedItemId; i > 0; i--) { - mViewItem[i] = mViewItem[i - 1]; + for (int i = removeAtBufferIndex; i > 0; i--) { + mViewItems[i] = mViewItems[i - 1]; } // pull data out from the DataAdapter for the first one. int curr = 0; int next = curr + 1; - if (mViewItem[next] != null) { - mViewItem[curr] = buildItemFromData(mViewItem[next].getId() - 1); + if (mViewItems[next] != null) { + mViewItems[curr] = buildViewItemAt(mViewItems[next].getAdapterIndex() - 1); + } // Translate the views to their original places. - for (int i = removedItemId; i >= 0; i--) { - if (mViewItem[i] != null) { - mViewItem[i].setTranslationX(-offsetX); + for (int i = removeAtBufferIndex; i >= 0; i--) { + if (mViewItems[i] != null) { + mViewItems[i].setTranslationX(-offsetX); } } } @@ -1467,100 +1489,105 @@ public class FilmstripView extends ViewGroup { invalidate(); // Now, slide every one back. - if (mViewItem[mCurrentItem] == null) { + if (mViewItems[BUFFER_CENTER] == null) { return; } for (int i = 0; i < BUFFER_SIZE; i++) { - if (mViewItem[i] != null - && mViewItem[i].getTranslationX() != 0f) { - slideViewBack(mViewItem[i]); + if (mViewItems[i] != null + && mViewItems[i].getTranslationX() != 0f) { + slideViewBack(mViewItems[i]); } } - if (isCurrentItemCentered() && isViewTypeSticky(mViewItem[mCurrentItem])) { + if (isCurrentItemCentered() && isViewTypeSticky(mViewItems[BUFFER_CENTER])) { // Special case for scrolling onto the camera preview after removal. mController.goToFullScreen(); } } // returns -1 on failure. - private int findItemByDataID(int dataID) { + private int findItemInBufferByAdapterIndex(int index) { for (int i = 0; i < BUFFER_SIZE; i++) { - if (mViewItem[i] != null - && mViewItem[i].getId() == dataID) { + if (mViewItems[i] != null + && mViewItems[i].getAdapterIndex() == index) { return i; } } return -1; } - private void updateInsertion(int dataID) { - int insertedItemId = findItemByDataID(dataID); - if (insertedItemId == -1) { + private void updateInsertion(int index) { + int bufferIndex = findItemInBufferByAdapterIndex(index); + if (bufferIndex == -1) { // Not in the current item buffers. Check if it's inserted // at the end. - if (dataID == mDataAdapter.getTotalNumber() - 1) { - int prev = findItemByDataID(dataID - 1); + if (index == mDataAdapter.getTotalNumber() - 1) { + int prev = findItemInBufferByAdapterIndex(index - 1); if (prev >= 0 && prev < BUFFER_SIZE - 1) { // The previous data is in the buffer and we still // have room for the inserted data. - insertedItemId = prev + 1; + bufferIndex = prev + 1; } } } - // adjust the data id to be consistent + // adjust the indexes to be consistent for (int i = 0; i < BUFFER_SIZE; i++) { - if (mViewItem[i] == null || mViewItem[i].getId() < dataID) { + if (mViewItems[i] == null || mViewItems[i].getAdapterIndex() < index) { continue; } - mViewItem[i].setId(mViewItem[i].getId() + 1); + mViewItems[i].setIndex(mViewItems[i].getAdapterIndex() + 1); } - if (insertedItemId == -1) { + if (bufferIndex == -1) { return; } - final ImageData data = mDataAdapter.getImageData(dataID); + final FilmstripItem data = mDataAdapter.getFilmstripItemAt(index); Point dim = CameraUtil - .resizeToFill(data.getWidth(), data.getHeight(), data.getRotation(), - getMeasuredWidth(), getMeasuredHeight()); + .resizeToFill( + data.getData().getDimensions().getWidth(), + data.getData().getDimensions().getHeight(), + data.getData().getOrientation(), + getMeasuredWidth(), + getMeasuredHeight()); final int offsetX = dim.x + mViewGapInPixel; - ViewItem viewItem = buildItemFromData(dataID); + ViewItem viewItem = buildViewItemAt(index); if (viewItem == null) { Log.w(TAG, "unable to build inserted item from data"); return; } - if (insertedItemId >= mCurrentItem) { - if (insertedItemId == mCurrentItem) { - viewItem.setLeftPosition(mViewItem[mCurrentItem].getLeftPosition()); + // TODO: Ensure newly visible items are loaded at full size. + if (bufferIndex >= BUFFER_CENTER) { + if (bufferIndex == BUFFER_CENTER) { + viewItem.setLeftPosition(mViewItems[BUFFER_CENTER].getLeftPosition()); } // Shift right to make rooms for newly inserted item. removeItem(BUFFER_SIZE - 1); - for (int i = BUFFER_SIZE - 1; i > insertedItemId; i--) { - mViewItem[i] = mViewItem[i - 1]; - if (mViewItem[i] != null) { - mViewItem[i].setTranslationX(-offsetX); - slideViewBack(mViewItem[i]); + for (int i = BUFFER_SIZE - 1; i > bufferIndex; i--) { + mViewItems[i] = mViewItems[i - 1]; + if (mViewItems[i] != null) { + mViewItems[i].setTranslationX(-offsetX); + slideViewBack(mViewItems[i]); } } } else { // Shift left. Put the inserted data on the left instead of the // found position. - --insertedItemId; - if (insertedItemId < 0) { + --bufferIndex; + if (bufferIndex < 0) { return; } removeItem(0); - for (int i = 1; i <= insertedItemId; i++) { - if (mViewItem[i] != null) { - mViewItem[i].setTranslationX(offsetX); - slideViewBack(mViewItem[i]); - mViewItem[i - 1] = mViewItem[i]; + for (int i = 1; i <= bufferIndex; i++) { + if (mViewItems[i] != null) { + mViewItems[i].setTranslationX(offsetX); + slideViewBack(mViewItems[i]); + mViewItems[i - 1] = mViewItems[i]; } } } - mViewItem[insertedItemId] = viewItem; + mViewItems[bufferIndex] = viewItem; viewItem.setAlpha(0f); viewItem.setTranslationY(getHeight() / 8); slideViewBack(viewItem); @@ -1568,41 +1595,47 @@ public class FilmstripView extends ViewGroup { invalidate(); } - private void setDataAdapter(DataAdapter adapter) { + private void setDataAdapter(FilmstripDataAdapter adapter) { mDataAdapter = adapter; int maxEdge = (int) (Math.max(this.getHeight(), this.getWidth()) * FILM_STRIP_SCALE); mDataAdapter.suggestViewSizeBound(maxEdge, maxEdge); - mDataAdapter.setListener(new DataAdapter.Listener() { + mDataAdapter.setListener(new FilmstripDataAdapter.Listener() { @Override - public void onDataLoaded() { + public void onFilmstripItemLoaded() { reload(); } @Override - public void onDataUpdated(DataAdapter.UpdateReporter reporter) { + public void onFilmstripItemUpdated(FilmstripDataAdapter.UpdateReporter reporter) { update(reporter); } @Override - public void onDataInserted(int dataId, ImageData data) { - if (mViewItem[mCurrentItem] == null) { + public void onFilmstripItemInserted(int index, FilmstripItem item) { + if (mViewItems[BUFFER_CENTER] == null) { // empty now, simply do a reload. reload(); } else { - updateInsertion(dataId); + updateInsertion(index); } if (mListener != null) { - mListener.onDataFocusChanged(dataId, getCurrentId()); + mListener.onDataFocusChanged(index, getCurrentItemAdapterIndex()); } + Log.d(TAG, "[ensureItemAtMaxSize] [ensureBufferItemsAtMaxSize]" + + " onFilmstripItemInserted()"); + ensureBufferItemsAtMaxSize(); } @Override - public void onDataRemoved(int dataId, ImageData data) { - animateItemRemoval(dataId, data); + public void onFilmstripItemRemoved(int index, FilmstripItem item) { + animateItemRemoval(index); if (mListener != null) { - mListener.onDataFocusChanged(dataId, getCurrentId()); + mListener.onDataFocusChanged(index, getCurrentItemAdapterIndex()); } + Log.d(TAG, "[ensureItemAtMaxSize] [ensureBufferItemsAtMaxSize]" + + " onFilmstripItemRemoved()"); + ensureBufferItemsAtMaxSize(); } }); } @@ -1620,12 +1653,12 @@ public class FilmstripView extends ViewGroup { } private boolean isCameraPreview() { - return isViewTypeSticky(mViewItem[mCurrentItem]); + return isViewTypeSticky(mViewItems[BUFFER_CENTER]); } private boolean inCameraFullscreen() { - return isDataAtCenter(0) && inFullScreen() - && (isViewTypeSticky(mViewItem[mCurrentItem])); + return isItemAtIndexCentered(0) && inFullScreen() + && (isViewTypeSticky(mViewItems[BUFFER_CENTER])); } @Override @@ -1637,9 +1670,10 @@ public class FilmstripView extends ViewGroup { if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { mCheckToIntercept = true; mDown = MotionEvent.obtain(ev); - ViewItem viewItem = mViewItem[mCurrentItem]; + ViewItem viewItem = mViewItems[BUFFER_CENTER]; // Do not intercept touch if swipe is not enabled - if (viewItem != null && !mDataAdapter.canSwipeInFullScreen(viewItem.getId())) { + if (viewItem != null && + !mDataAdapter.canSwipeInFullScreen(viewItem.getAdapterIndex())) { mCheckToIntercept = false; } return false; @@ -1682,15 +1716,15 @@ public class FilmstripView extends ViewGroup { return mGestureListener; } - private void updateViewItem(int itemID) { - ViewItem item = mViewItem[itemID]; + private void updateViewItem(int bufferIndex) { + ViewItem item = mViewItems[bufferIndex]; if (item == null) { Log.e(TAG, "trying to update an null item"); return; } item.removeViewFromHierarchy(true); - ViewItem newItem = buildItemFromData(item.getId()); + ViewItem newItem = buildViewItemAt(item.getAdapterIndex()); if (newItem == null) { Log.e(TAG, "new item is null"); // keep using the old data. @@ -1698,82 +1732,89 @@ public class FilmstripView extends ViewGroup { return; } newItem.copyAttributes(item); - mViewItem[itemID] = newItem; + mViewItems[bufferIndex] = newItem; mZoomView.resetDecoder(); boolean stopScroll = clampCenterX(); if (stopScroll) { mController.stopScrolling(true); } + + Log.d(TAG, "[ensureItemAtMaxSize] updateViewItem()"); + adjustChildZOrder(); invalidate(); if (mListener != null) { - mListener.onDataUpdated(newItem.getId()); + mListener.onDataUpdated(newItem.getAdapterIndex()); } } /** Some of the data is changed. */ - private void update(DataAdapter.UpdateReporter reporter) { + private void update(FilmstripDataAdapter.UpdateReporter reporter) { // No data yet. - if (mViewItem[mCurrentItem] == null) { + if (mViewItems[BUFFER_CENTER] == null) { reload(); return; } // Check the current one. - ViewItem curr = mViewItem[mCurrentItem]; - int dataId = curr.getId(); - if (reporter.isDataRemoved(dataId)) { + ViewItem curr = mViewItems[BUFFER_CENTER]; + int index = curr.getAdapterIndex(); + if (reporter.isDataRemoved(index)) { reload(); return; } - if (reporter.isDataUpdated(dataId)) { - updateViewItem(mCurrentItem); - final ImageData data = mDataAdapter.getImageData(dataId); + if (reporter.isDataUpdated(index)) { + updateViewItem(BUFFER_CENTER); + final FilmstripItem data = mDataAdapter.getFilmstripItemAt(index); if (!mIsUserScrolling && !mController.isScrolling()) { // If there is no scrolling at all, adjust mCenterX to place // the current item at the center. - Point dim = CameraUtil.resizeToFill(data.getWidth(), data.getHeight(), - data.getRotation(), getMeasuredWidth(), getMeasuredHeight()); + Point dim = CameraUtil.resizeToFill( + data.getData().getDimensions().getWidth(), + data.getData().getDimensions().getHeight(), + data.getData().getOrientation(), + getMeasuredWidth(), + getMeasuredHeight()); mCenterX = curr.getLeftPosition() + dim.x / 2; } } // Check left - for (int i = mCurrentItem - 1; i >= 0; i--) { - curr = mViewItem[i]; + for (int i = BUFFER_CENTER - 1; i >= 0; i--) { + curr = mViewItems[i]; if (curr != null) { - dataId = curr.getId(); - if (reporter.isDataRemoved(dataId) || reporter.isDataUpdated(dataId)) { + index = curr.getAdapterIndex(); + if (reporter.isDataRemoved(index) || reporter.isDataUpdated(index)) { updateViewItem(i); } + } else { - ViewItem next = mViewItem[i + 1]; + ViewItem next = mViewItems[i + 1]; if (next != null) { - mViewItem[i] = buildItemFromData(next.getId() - 1); + mViewItems[i] = buildViewItemAt(next.getAdapterIndex() - 1); } } } // Check right - for (int i = mCurrentItem + 1; i < BUFFER_SIZE; i++) { - curr = mViewItem[i]; + for (int i = BUFFER_CENTER + 1; i < BUFFER_SIZE; i++) { + curr = mViewItems[i]; if (curr != null) { - dataId = curr.getId(); - if (reporter.isDataRemoved(dataId) || reporter.isDataUpdated(dataId)) { + index = curr.getAdapterIndex(); + if (reporter.isDataRemoved(index) || reporter.isDataUpdated(index)) { updateViewItem(i); } } else { - ViewItem prev = mViewItem[i - 1]; + ViewItem prev = mViewItems[i - 1]; if (prev != null) { - mViewItem[i] = buildItemFromData(prev.getId() + 1); + mViewItems[i] = buildViewItemAt(prev.getAdapterIndex() + 1); } } } adjustChildZOrder(); // Request a layout to find the measured width/height of the view first. requestLayout(); - // Update photo sphere visibility after metadata fully written. } /** @@ -1784,108 +1825,111 @@ public class FilmstripView extends ViewGroup { private void reload() { mController.stopScrolling(true); mController.stopScale(); - mDataIdOnUserScrolling = 0; + mAdapterIndexUserIsScrollingOver = 0; int prevId = -1; - if (mViewItem[mCurrentItem] != null) { - prevId = mViewItem[mCurrentItem].getId(); + if (mViewItems[BUFFER_CENTER] != null) { + prevId = mViewItems[BUFFER_CENTER].getAdapterIndex(); } - // Remove all views from the mViewItem buffer, except the camera view. - for (int i = 0; i < mViewItem.length; i++) { - if (mViewItem[i] == null) { + // Remove all views from the mViewItems buffer, except the camera view. + for (int i = 0; i < mViewItems.length; i++) { + if (mViewItems[i] == null) { continue; } - mViewItem[i].removeViewFromHierarchy(false); + mViewItems[i].removeViewFromHierarchy(false); } // Clear out the mViewItems and rebuild with camera in the center. - Arrays.fill(mViewItem, null); + Arrays.fill(mViewItems, null); int dataNumber = mDataAdapter.getTotalNumber(); if (dataNumber == 0) { return; } - mViewItem[mCurrentItem] = buildItemFromData(0); - if (mViewItem[mCurrentItem] == null) { + mViewItems[BUFFER_CENTER] = buildViewItemAt(0); + if (mViewItems[BUFFER_CENTER] == null) { return; } - mViewItem[mCurrentItem].setLeftPosition(0); - for (int i = mCurrentItem + 1; i < BUFFER_SIZE; i++) { - mViewItem[i] = buildItemFromData(mViewItem[i - 1].getId() + 1); - if (mViewItem[i] == null) { + mViewItems[BUFFER_CENTER].setLeftPosition(0); + for (int i = BUFFER_CENTER + 1; i < BUFFER_SIZE; i++) { + mViewItems[i] = buildViewItemAt(mViewItems[i - 1].getAdapterIndex() + 1); + if (mViewItems[i] == null) { break; } } - // Ensure that the views in mViewItem will layout the first in the + // Ensure that the views in mViewItems will layout the first in the // center of the display upon a reload. mCenterX = -1; mScale = FILM_STRIP_SCALE; adjustChildZOrder(); + + Log.d(TAG, "[ensureItemAtMaxSize] [ensureBufferItemsAtMaxSize] reload()"); + ensureBufferItemsAtMaxSize(); invalidate(); if (mListener != null) { mListener.onDataReloaded(); - mListener.onDataFocusChanged(prevId, mViewItem[mCurrentItem].getId()); + mListener.onDataFocusChanged(prevId, mViewItems[BUFFER_CENTER].getAdapterIndex()); } } - private void promoteData(int itemID, int dataID) { + private void promoteData(int index) { if (mListener != null) { - mListener.onFocusedDataPromoted(dataID); + mListener.onFocusedDataPromoted(index); } } - private void demoteData(int itemID, int dataID) { + private void demoteData(int index) { if (mListener != null) { - mListener.onFocusedDataDemoted(dataID); + mListener.onFocusedDataDemoted(index); } } private void onEnterFilmstrip() { if (mListener != null) { - mListener.onEnterFilmstrip(getCurrentId()); + mListener.onEnterFilmstrip(getCurrentItemAdapterIndex()); } } private void onLeaveFilmstrip() { if (mListener != null) { - mListener.onLeaveFilmstrip(getCurrentId()); + mListener.onLeaveFilmstrip(getCurrentItemAdapterIndex()); } } private void onEnterFullScreen() { mFullScreenUIHidden = false; if (mListener != null) { - mListener.onEnterFullScreenUiShown(getCurrentId()); + mListener.onEnterFullScreenUiShown(getCurrentItemAdapterIndex()); } } private void onLeaveFullScreen() { if (mListener != null) { - mListener.onLeaveFullScreenUiShown(getCurrentId()); + mListener.onLeaveFullScreenUiShown(getCurrentItemAdapterIndex()); } } private void onEnterFullScreenUiHidden() { mFullScreenUIHidden = true; if (mListener != null) { - mListener.onEnterFullScreenUiHidden(getCurrentId()); + mListener.onEnterFullScreenUiHidden(getCurrentItemAdapterIndex()); } } private void onLeaveFullScreenUiHidden() { mFullScreenUIHidden = false; if (mListener != null) { - mListener.onLeaveFullScreenUiHidden(getCurrentId()); + mListener.onLeaveFullScreenUiHidden(getCurrentItemAdapterIndex()); } } private void onEnterZoomView() { if (mListener != null) { - mListener.onEnterZoomView(getCurrentId()); + mListener.onEnterZoomView(getCurrentItemAdapterIndex()); } } @@ -1897,23 +1941,26 @@ public class FilmstripView extends ViewGroup { * MyController controls all the geometry animations. It passively tells the * geometry information on demand. */ - private class MyController implements FilmstripController { + private class FilmstripControllerImpl implements FilmstripController { private final ValueAnimator mScaleAnimator; private ValueAnimator mZoomAnimator; private AnimatorSet mFlingAnimator; - private final MyScroller mScroller; + private final FilmstripScrollGesture mScrollGesture; private boolean mCanStopScroll; - private final MyScroller.Listener mScrollerListener = - new MyScroller.Listener() { + private final FilmstripScrollGesture.Listener mScrollListener = + new FilmstripScrollGesture.Listener() { @Override public void onScrollUpdate(int currX, int currY) { mCenterX = currX; + Log.e(TAG, "[fling] onScrollUpdate X: " + currX + ", Y: " + currY); + boolean stopScroll = clampCenterX(); if (stopScroll) { + Log.e(TAG, "[fling] stopScrolling!"); mController.stopScrolling(true); } invalidate(); @@ -1922,12 +1969,29 @@ public class FilmstripView extends ViewGroup { @Override public void onScrollEnd() { mCanStopScroll = true; - if (mViewItem[mCurrentItem] == null) { + Log.e(TAG, "[fling] onScrollEnd " + BUFFER_CENTER); + if (mViewItems[BUFFER_CENTER] == null) { return; } - snapInCenter(); + scrollCurrentItemToCenter(); + + // onScrollEnd will get called twice, once when + // the fling part ends, and once when the manual + // scroll center animation finishes. Once everything + // stops moving ensure that the items are loaded at + // full resolution. + if (isCurrentItemCentered()) { + // Since these are getting pushed into a queue, + // we want to ensure the item that is "most in view" is + // the first one rendered at max size. + ensureItemAtMaxSize(BUFFER_CENTER); + ensureItemAtMaxSize(BUFFER_CENTER + 1); + ensureItemAtMaxSize(BUFFER_CENTER - 1); + ensureItemAtMaxSize(BUFFER_CENTER + 2); + } + if (isCurrentItemCentered() - && isViewTypeSticky(mViewItem[mCurrentItem])) { + && isViewTypeSticky(mViewItems[BUFFER_CENTER])) { // Special case for the scrolling end on the camera // preview. goToFullScreen(); @@ -1939,7 +2003,7 @@ public class FilmstripView extends ViewGroup { new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - if (mViewItem[mCurrentItem] == null) { + if (mViewItems[BUFFER_CENTER] == null) { return; } mScale = (Float) animation.getAnimatedValue(); @@ -1947,11 +2011,11 @@ public class FilmstripView extends ViewGroup { } }; - MyController(Context context) { + FilmstripControllerImpl() { TimeInterpolator decelerateInterpolator = new DecelerateInterpolator(1.5f); - mScroller = new MyScroller(mActivity.getAndroidContext(), + mScrollGesture = new FilmstripScrollGesture(mActivity.getAndroidContext(), new Handler(mActivity.getMainLooper()), - mScrollerListener, decelerateInterpolator); + mScrollListener, decelerateInterpolator); mCanStopScroll = true; mScaleAnimator = new ValueAnimator(); @@ -1999,12 +2063,12 @@ public class FilmstripView extends ViewGroup { } @Override - public int getCurrentId() { - return FilmstripView.this.getCurrentId(); + public int getCurrentAdapterIndex() { + return FilmstripView.this.getCurrentItemAdapterIndex(); } @Override - public void setDataAdapter(DataAdapter adapter) { + public void setDataAdapter(FilmstripDataAdapter adapter) { FilmstripView.this.setDataAdapter(adapter); } @@ -2029,13 +2093,13 @@ public class FilmstripView extends ViewGroup { } @Override - public void setListener(FilmstripListener l) { - FilmstripView.this.setListener(l); + public void setListener(FilmstripListener listener) { + FilmstripView.this.setListener(listener); } @Override public boolean isScrolling() { - return !mScroller.isFinished(); + return !mScrollGesture.isFinished(); } @Override @@ -2043,13 +2107,13 @@ public class FilmstripView extends ViewGroup { return mScaleAnimator.isRunning(); } - private int estimateMinX(int dataID, int leftPos, int viewWidth) { - return leftPos - (dataID + 100) * (viewWidth + mViewGapInPixel); + private int estimateMinX(int index, int leftPos, int viewWidth) { + return leftPos - (index + 100) * (viewWidth + mViewGapInPixel); } - private int estimateMaxX(int dataID, int leftPos, int viewWidth) { + private int estimateMaxX(int index, int leftPos, int viewWidth) { return leftPos - + (mDataAdapter.getTotalNumber() - dataID + 100) + + (mDataAdapter.getTotalNumber() - index + 100) * (viewWidth + mViewGapInPixel); } @@ -2149,7 +2213,7 @@ public class FilmstripView extends ViewGroup { if (!stopScrolling(false)) { return; } - final ViewItem item = mViewItem[mCurrentItem]; + final ViewItem item = mViewItems[BUFFER_CENTER]; if (item == null) { return; } @@ -2164,11 +2228,11 @@ public class FilmstripView extends ViewGroup { // Estimation of possible length on the left. To ensure the // velocity doesn't become too slow eventually, we add a huge number // to the estimated maximum. - int minX = estimateMinX(item.getId(), item.getLeftPosition(), w); + int minX = estimateMinX(item.getAdapterIndex(), item.getLeftPosition(), w); // Estimation of possible length on the right. Likewise, exaggerate // the possible maximum too. - int maxX = estimateMaxX(item.getId(), item.getLeftPosition(), w); - mScroller.fling(mCenterX, 0, (int) -velocityX, 0, minX, maxX, 0, 0); + int maxX = estimateMaxX(item.getAdapterIndex(), item.getLeftPosition(), w); + mScrollGesture.fling(mCenterX, 0, (int) -velocityX, 0, minX, maxX, 0, 0); } void flingInsideZoomView(float velocityX, float velocityY) { @@ -2176,7 +2240,7 @@ public class FilmstripView extends ViewGroup { return; } - final ViewItem current = mViewItem[mCurrentItem]; + final ViewItem current = mViewItems[BUFFER_CENTER]; if (current == null) { return; } @@ -2266,7 +2330,7 @@ public class FilmstripView extends ViewGroup { } else if (!mCanStopScroll && !forced) { return false; } - mScroller.forceFinished(true); + mScrollGesture.forceFinished(true); return true; } @@ -2276,32 +2340,32 @@ public class FilmstripView extends ViewGroup { @Override public void scrollToPosition(int position, int duration, boolean interruptible) { - if (mViewItem[mCurrentItem] == null) { + if (mViewItems[BUFFER_CENTER] == null) { return; } mCanStopScroll = interruptible; - mScroller.startScroll(mCenterX, 0, position - mCenterX, 0, duration); + mScrollGesture.startScroll(mCenterX, position - mCenterX, duration); } @Override public boolean goToNextItem() { - return goToItem(mCurrentItem + 1); + return goToItem(BUFFER_CENTER + 1); } @Override public boolean goToPreviousItem() { - return goToItem(mCurrentItem - 1); + return goToItem(BUFFER_CENTER - 1); } private boolean goToItem(int itemIndex) { - final ViewItem nextItem = mViewItem[itemIndex]; + final ViewItem nextItem = mViewItems[itemIndex]; if (nextItem == null) { return false; } stopScrolling(true); scrollToPosition(nextItem.getCenterX(), GEOMETRY_ADJUST_TIME_MS * 2, false); - if (isViewTypeSticky(mViewItem[mCurrentItem])) { + if (isViewTypeSticky(mViewItems[BUFFER_CENTER])) { // Special case when moving from camera preview. scaleTo(FILM_STRIP_SCALE, GEOMETRY_ADJUST_TIME_MS); } @@ -2309,7 +2373,7 @@ public class FilmstripView extends ViewGroup { } private void scaleTo(float scale, int duration) { - if (mViewItem[mCurrentItem] == null) { + if (mViewItems[BUFFER_CENTER] == null) { return; } stopScale(); @@ -2320,7 +2384,7 @@ public class FilmstripView extends ViewGroup { @Override public void goToFilmstrip() { - if (mViewItem[mCurrentItem] == null) { + if (mViewItems[BUFFER_CENTER] == null) { return; } if (mScale == FILM_STRIP_SCALE) { @@ -2328,9 +2392,9 @@ public class FilmstripView extends ViewGroup { } scaleTo(FILM_STRIP_SCALE, GEOMETRY_ADJUST_TIME_MS); - final ViewItem currItem = mViewItem[mCurrentItem]; - final ViewItem nextItem = mViewItem[mCurrentItem + 1]; - if (currItem.getId() == 0 && isViewTypeSticky(currItem) && nextItem != null) { + final ViewItem currItem = mViewItems[BUFFER_CENTER]; + final ViewItem nextItem = mViewItems[BUFFER_CENTER + 1]; + if (currItem.getAdapterIndex() == 0 && isViewTypeSticky(currItem) && nextItem != null) { // Deal with the special case of swiping in camera preview. scrollToPosition(nextItem.getCenterX(), GEOMETRY_ADJUST_TIME_MS, false); } @@ -2366,20 +2430,19 @@ public class FilmstripView extends ViewGroup { // Hide everything on the left // TODO: Need to find a better way to toggle the visibility of views // around the current view. - for (int i = 0; i < mCurrentItem; i++) { - if (i == mCurrentItem || mViewItem[i] == null) { - continue; + for (int i = 0; i < BUFFER_CENTER; i++) { + if (mViewItems[i] != null) { + mViewItems[i].setVisibility(visible ? VISIBLE : INVISIBLE); } - mViewItem[i].setVisibility(visible ? VISIBLE : INVISIBLE); } } private Uri getCurrentUri() { - ViewItem curr = mViewItem[mCurrentItem]; + ViewItem curr = mViewItems[BUFFER_CENTER]; if (curr == null) { return Uri.EMPTY; } - return mDataAdapter.getImageData(curr.getId()).getUri(); + return mDataAdapter.getFilmstripItemAt(curr.getAdapterIndex()).getData().getUri(); } /** @@ -2388,18 +2451,18 @@ public class FilmstripView extends ViewGroup { * make the view same size as the image, in pixels. */ private float getCurrentDataMaxScale(boolean allowOverScale) { - ViewItem curr = mViewItem[mCurrentItem]; + ViewItem curr = mViewItems[BUFFER_CENTER]; if (curr == null) { return FULL_SCREEN_SCALE; } - ImageData imageData = mDataAdapter.getImageData(curr.getId()); - if (imageData == null || !imageData.isUIActionSupported(ImageData.ACTION_ZOOM)) { + FilmstripItem imageData = mDataAdapter.getFilmstripItemAt(curr.getAdapterIndex()); + if (imageData == null || !imageData.getAttributes().canZoomInPlace()) { return FULL_SCREEN_SCALE; } - float imageWidth = imageData.getWidth(); - if (imageData.getRotation() == 90 - || imageData.getRotation() == 270) { - imageWidth = imageData.getHeight(); + float imageWidth = imageData.getData().getDimensions().getWidth(); + if (imageData.getData().getOrientation() == 90 + || imageData.getData().getOrientation() == 270) { + imageWidth = imageData.getData().getDimensions().getHeight(); } float scale = imageWidth / curr.getWidth(); if (allowOverScale) { @@ -2415,12 +2478,12 @@ public class FilmstripView extends ViewGroup { if (!inZoomView()) { return; } - ViewItem curr = mViewItem[mCurrentItem]; + ViewItem curr = mViewItems[BUFFER_CENTER]; if (curr == null) { return; } - ImageData imageData = mDataAdapter.getImageData(curr.getId()); - if (!imageData.isUIActionSupported(ImageData.ACTION_ZOOM)) { + FilmstripItem imageData = mDataAdapter.getFilmstripItemAt(curr.getAdapterIndex()); + if (!imageData.getAttributes().canZoomInPlace()) { return; } Uri uri = getCurrentUri(); @@ -2428,7 +2491,7 @@ public class FilmstripView extends ViewGroup { if (uri == null || uri == Uri.EMPTY) { return; } - int orientation = imageData.getRotation(); + int orientation = imageData.getData().getOrientation(); mZoomView.loadBitmap(uri, orientation, viewRect); } @@ -2438,11 +2501,11 @@ public class FilmstripView extends ViewGroup { @Override public void goToFirstItem() { - if (mViewItem[mCurrentItem] == null) { + if (mViewItems[BUFFER_CENTER] == null) { return; } resetZoomView(); - // TODO: animate to camera if it is still in the mViewItem buffer + // TODO: animate to camera if it is still in the mViewItems buffer // versus a full reload which will perform an immediate transition reload(); } @@ -2461,10 +2524,10 @@ public class FilmstripView extends ViewGroup { } private boolean isCurrentItemCentered() { - return mViewItem[mCurrentItem].getCenterX() == mCenterX; + return mViewItems[BUFFER_CENTER].getCenterX() == mCenterX; } - private static class MyScroller { + private static class FilmstripScrollGesture { public interface Listener { public void onScrollUpdate(int currX, int currY); @@ -2482,6 +2545,7 @@ public class FilmstripView extends ViewGroup { public void run() { boolean newPosition = mScroller.computeScrollOffset(); if (!newPosition) { + Log.e(TAG, "[fling] onScrollEnd from computeScrollOffset"); mListener.onScrollEnd(); return; } @@ -2503,27 +2567,32 @@ public class FilmstripView extends ViewGroup { new Animator.AnimatorListener() { @Override public void onAnimationCancel(Animator animation) { + Log.e(TAG, "[fling] mXScrollAnimatorListener.onAnimationCancel"); // Do nothing. } @Override public void onAnimationEnd(Animator animation) { + + Log.e(TAG, "[fling] onScrollEnd from mXScrollAnimatorListener.onAnimationEnd"); mListener.onScrollEnd(); } @Override public void onAnimationRepeat(Animator animation) { + Log.e(TAG, "[fling] mXScrollAnimatorListener.onAnimationRepeat"); // Do nothing. } @Override public void onAnimationStart(Animator animation) { + Log.e(TAG, "[fling] mXScrollAnimatorListener.onAnimationStart"); // Do nothing. } }; - public MyScroller(Context ctx, Handler handler, Listener listener, - TimeInterpolator interpolator) { + public FilmstripScrollGesture(Context ctx, Handler handler, Listener listener, + TimeInterpolator interpolator) { mHandler = handler; mListener = listener; mScroller = new Scroller(ctx); @@ -2548,7 +2617,7 @@ public class FilmstripView extends ViewGroup { } /** Only starts and updates scroll in x-axis. */ - public void startScroll(int startX, int startY, int dx, int dy, int duration) { + public void startScroll(int startX, int dx, int duration) { mXScrollAnimator.cancel(); mXScrollAnimator.setDuration(duration); mXScrollAnimator.setIntValues(startX, startX + dx); @@ -2575,7 +2644,7 @@ public class FilmstripView extends ViewGroup { } } - private class MyGestureReceiver implements FilmstripGestureRecognizer.Listener { + private class FilmstripGestures implements FilmstripGestureRecognizer.Listener { private static final int SCROLL_DIR_NONE = 0; private static final int SCROLL_DIR_VERTICAL = 1; @@ -2589,7 +2658,7 @@ public class FilmstripView extends ViewGroup { @Override public boolean onSingleTapUp(float x, float y) { - ViewItem centerItem = mViewItem[mCurrentItem]; + ViewItem centerItem = mViewItems[BUFFER_CENTER]; if (inFilmstrip()) { if (centerItem != null && centerItem.areaContains(x, y)) { mController.goToFullScreen(); @@ -2610,7 +2679,7 @@ public class FilmstripView extends ViewGroup { @Override public boolean onDoubleTap(float x, float y) { - ViewItem current = mViewItem[mCurrentItem]; + ViewItem current = mViewItems[BUFFER_CENTER]; if (current == null) { return false; } @@ -2625,7 +2694,7 @@ public class FilmstripView extends ViewGroup { } if (inFullScreen()) { mController.zoomAt(current, x, y); - checkItemAtMaxSize(); + ensureItemAtMaxSize(BUFFER_CENTER); return true; } else if (mScale > FULL_SCREEN_SCALE) { // In zoom view. @@ -2648,7 +2717,7 @@ public class FilmstripView extends ViewGroup { @Override public boolean onUp(float x, float y) { - ViewItem currItem = mViewItem[mCurrentItem]; + ViewItem currItem = mViewItems[BUFFER_CENTER]; if (currItem == null) { return false; } @@ -2667,88 +2736,86 @@ public class FilmstripView extends ViewGroup { float speedY = Math.abs(y - mLastDownY) / (SystemClock.uptimeMillis() - mLastDownTime); for (int i = 0; i < BUFFER_SIZE; i++) { - if (mViewItem[i] == null) { + if (mViewItems[i] == null) { continue; } - float transY = mViewItem[i].getTranslationY(); + float transY = mViewItems[i].getTranslationY(); if (transY == 0) { continue; } - int id = mViewItem[i].getId(); + int index = mViewItems[i].getAdapterIndex(); - if (mDataAdapter.getImageData(id) - .isUIActionSupported(ImageData.ACTION_DEMOTE) + if (mDataAdapter.getFilmstripItemAt(index).getAttributes().canSwipeAway() && ((transY > promoteHeight) || (transY > velocityPromoteHeight && speedY > PROMOTE_VELOCITY))) { - demoteData(i, id); - } else if (mDataAdapter.getImageData(id) - .isUIActionSupported(ImageData.ACTION_PROMOTE) + demoteData(index); + } else if (mDataAdapter.getFilmstripItemAt(index).getAttributes().canSwipeAway() && (transY < -promoteHeight || (transY < -velocityPromoteHeight && speedY > PROMOTE_VELOCITY))) { - promoteData(i, id); + promoteData(index); } else { // put the view back. - slideViewBack(mViewItem[i]); + slideViewBack(mViewItems[i]); } } // The data might be changed. Re-check. - currItem = mViewItem[mCurrentItem]; + currItem = mViewItems[BUFFER_CENTER]; if (currItem == null) { return true; } - int currId = currItem.getId(); + int currId = currItem.getAdapterIndex(); if (mCenterX > currItem.getCenterX() + CAMERA_PREVIEW_SWIPE_THRESHOLD && currId == 0 && - isViewTypeSticky(currItem) && mDataIdOnUserScrolling == 0) { + isViewTypeSticky(currItem) && mAdapterIndexUserIsScrollingOver == 0) { mController.goToFilmstrip(); // Special case to go from camera preview to the next photo. - if (mViewItem[mCurrentItem + 1] != null) { + if (mViewItems[BUFFER_CENTER + 1] != null) { mController.scrollToPosition( - mViewItem[mCurrentItem + 1].getCenterX(), + mViewItems[BUFFER_CENTER + 1].getCenterX(), GEOMETRY_ADJUST_TIME_MS, false); } else { // No next photo. - snapInCenter(); + scrollCurrentItemToCenter(); } } if (isCurrentItemCentered() && currId == 0 && isViewTypeSticky(currItem)) { mController.goToFullScreen(); } else { - if (mDataIdOnUserScrolling == 0 && currId != 0) { + if (mAdapterIndexUserIsScrollingOver == 0 && currId != 0) { // Special case to go to filmstrip when the user scroll away // from the camera preview and the current one is not the // preview anymore. mController.goToFilmstrip(); - mDataIdOnUserScrolling = currId; + mAdapterIndexUserIsScrollingOver = currId; } - snapInCenter(); + scrollCurrentItemToCenter(); } return false; } @Override public void onLongPress(float x, float y) { - final int dataId = getCurrentId(); - if (dataId == -1) { + final int index = getCurrentItemAdapterIndex(); + if (index == -1) { return; } - mListener.onFocusedDataLongPressed(dataId); + mListener.onFocusedDataLongPressed(index); } @Override public boolean onScroll(float x, float y, float dx, float dy) { - final ViewItem currItem = mViewItem[mCurrentItem]; + final ViewItem currItem = mViewItems[BUFFER_CENTER]; if (currItem == null) { return false; } - if (inFullScreen() && !mDataAdapter.canSwipeInFullScreen(currItem.getId())) { + if (inFullScreen() && !mDataAdapter.canSwipeInFullScreen(currItem.getAdapterIndex())) { return false; } hideZoomView(); // When image is zoomed in to be bigger than the screen if (inZoomView()) { - ViewItem curr = mViewItem[mCurrentItem]; + ViewItem curr = mViewItems[BUFFER_CENTER]; float transX = curr.getTranslationX() * mScale - dx; float transY = curr.getTranslationY() * mScale - dy; curr.updateTransform(transX, transY, mScale, mScale, mDrawArea.width(), @@ -2760,7 +2827,8 @@ public class FilmstripView extends ViewGroup { mController.stopScrolling(true); if (!mIsUserScrolling) { mIsUserScrolling = true; - mDataIdOnUserScrolling = mViewItem[mCurrentItem].getId(); + mAdapterIndexUserIsScrollingOver = + mViewItems[BUFFER_CENTER].getAdapterIndex(); } if (inFilmstrip()) { // Disambiguate horizontal/vertical first. @@ -2769,7 +2837,8 @@ public class FilmstripView extends ViewGroup { SCROLL_DIR_VERTICAL; } if (mScrollingDirection == SCROLL_DIR_HORIZONTAL) { - if (mCenterX == currItem.getCenterX() && currItem.getId() == 0 && dx < 0) { + if (mCenterX == currItem.getCenterX() && currItem.getAdapterIndex() == 0 && + dx < 0) { // Already at the beginning, don't process the swipe. mIsUserScrolling = false; mScrollingDirection = SCROLL_DIR_NONE; @@ -2781,10 +2850,10 @@ public class FilmstripView extends ViewGroup { int hit = 0; Rect hitRect = new Rect(); for (; hit < BUFFER_SIZE; hit++) { - if (mViewItem[hit] == null) { + if (mViewItems[hit] == null) { continue; } - mViewItem[hit].getHitRect(hitRect); + mViewItems[hit].getHitRect(hitRect); if (hitRect.contains((int) x, (int) y)) { break; } @@ -2794,21 +2863,22 @@ public class FilmstripView extends ViewGroup { return true; } - ImageData data = mDataAdapter.getImageData(mViewItem[hit].getId()); - float transY = mViewItem[hit].getTranslationY() - dy / mScale; - if (!data.isUIActionSupported(ImageData.ACTION_DEMOTE) && + FilmstripItem data = mDataAdapter.getFilmstripItemAt( + mViewItems[hit].getAdapterIndex()); + float transY = mViewItems[hit].getTranslationY() - dy / mScale; + if (!data.getAttributes().canSwipeAway() && transY > 0f) { transY = 0f; } - if (!data.isUIActionSupported(ImageData.ACTION_PROMOTE) && + if (!data.getAttributes().canSwipeAway() && transY < 0f) { transY = 0f; } - mViewItem[hit].setTranslationY(transY); + mViewItems[hit].setTranslationY(transY); } } else if (inFullScreen()) { - if (mViewItem[mCurrentItem] == null || (deltaX < 0 && mCenterX <= - currItem.getCenterX() && currItem.getId() == 0)) { + if (mViewItems[BUFFER_CENTER] == null || (deltaX < 0 && mCenterX <= + currItem.getCenterX() && currItem.getAdapterIndex() == 0)) { return false; } // Multiplied by 1.2 to make it more easy to swipe. @@ -2845,11 +2915,11 @@ public class FilmstripView extends ViewGroup { @Override public boolean onFling(float velocityX, float velocityY) { - final ViewItem currItem = mViewItem[mCurrentItem]; + final ViewItem currItem = mViewItems[BUFFER_CENTER]; if (currItem == null) { return false; } - if (!mDataAdapter.canSwipeInFullScreen(currItem.getId())) { + if (!mDataAdapter.canSwipeInFullScreen(currItem.getAdapterIndex())) { return false; } if (inZoomView()) { @@ -2875,7 +2945,7 @@ public class FilmstripView extends ViewGroup { currItemCenterX, GEOMETRY_ADJUST_TIME_MS, true); return true; } - ViewItem prevItem = mViewItem[mCurrentItem - 1]; + ViewItem prevItem = mViewItems[BUFFER_CENTER - 1]; if (prevItem == null) { return false; } @@ -2890,7 +2960,7 @@ public class FilmstripView extends ViewGroup { currItemCenterX, GEOMETRY_ADJUST_TIME_MS, true); return true; } - final ViewItem nextItem = mViewItem[mCurrentItem + 1]; + final ViewItem nextItem = mViewItems[BUFFER_CENTER + 1]; if (nextItem == null) { return false; } @@ -2978,7 +3048,7 @@ public class FilmstripView extends ViewGroup { if (!inZoomView()) { mController.setSurroundingViewsVisible(false); } - ViewItem curr = mViewItem[mCurrentItem]; + ViewItem curr = mViewItems[BUFFER_CENTER]; // Make sure the image is not overly scaled newScale = Math.min(newScale, mMaxScale); if (newScale == mScale) { @@ -2992,7 +3062,7 @@ public class FilmstripView extends ViewGroup { } else { onEnterZoomView(); } - checkItemAtMaxSize(); + ensureItemAtMaxSize(BUFFER_CENTER); } return true; } |