1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Rect; 218bc5bebba780ca4a322b466b06fc909331697cf4Owen Linimport android.os.Handler; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.GestureDetector; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.animation.DecelerateInterpolator; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 26dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport com.android.gallery3d.anim.Animation; 2748ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Linimport com.android.gallery3d.app.GalleryActivity; 28dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport com.android.gallery3d.common.Utils; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class SlotView extends GLView { 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "SlotView"; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final boolean WIDE = true; 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int INDEX_NONE = -1; 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 377260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin public static final int RENDER_MORE_PASS = 1; 387260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin public static final int RENDER_MORE_FRAME = 2; 397260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public interface Listener { 41bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public void onDown(int index); 4290fe70f11b0961e1e5ae353cdf563236a55f502dYuli Huang public void onUp(boolean followedByLongPress); 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSingleTapUp(int index); 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onLongTap(int index); 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onScrollPositionChanged(int position, int total); 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static class SimpleListener implements Listener { 497260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin @Override public void onDown(int index) {} 5090fe70f11b0961e1e5ae353cdf563236a55f502dYuli Huang @Override public void onUp(boolean followedByLongPress) {} 517260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin @Override public void onSingleTapUp(int index) {} 527260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin @Override public void onLongTap(int index) {} 537260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin @Override public void onScrollPositionChanged(int position, int total) {} 547260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin } 557260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin 567260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin public static interface SlotRenderer { 577260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin public void prepareDrawing(); 587260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin public void onVisibleRangeChanged(int visibleStart, int visibleEnd); 591a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin public void onSlotSizeChanged(int width, int height); 607260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin public int renderSlot(GLCanvas canvas, int index, int pass, int width, int height); 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final GestureDetector mGestureDetector; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ScrollerHelper mScroller; 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Paper mPaper = new Paper(); 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Listener mListener; 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private UserInteractionListener mUIListener; 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mMoreAnimation = false; 712341c197b0becf99422e8ad305def77df6161714Owen Lin private SlotAnimation mAnimation = null; 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Layout mLayout = new Layout(); 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mStartIndex = INDEX_NONE; 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // whether the down action happened while the view is scrolling. 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mDownInScrolling; 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mOverscrollEffect = OVERSCROLL_3D; 788bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin private final Handler mHandler; 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 807260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin private SlotRenderer mRenderer; 817260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin 827260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin private int[] mRequestRenderSlots = new int[16]; 837260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int OVERSCROLL_3D = 0; 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int OVERSCROLL_SYSTEM = 1; 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int OVERSCROLL_NONE = 2; 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 88d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin // to prevent allocating memory 89d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin private final Rect mTempRect = new Rect(); 90d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin 9148ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin public SlotView(GalleryActivity activity, Spec spec) { 9248ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin mGestureDetector = new GestureDetector( 9348ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin (Context) activity, new MyGestureListener()); 9448ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin mScroller = new ScrollerHelper((Context) activity); 9548ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin mHandler = new SynchronizedHandler(activity.getGLRoot()); 967260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin setSlotSpec(spec); 977260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin } 987260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin 997260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin public void setSlotRenderer(SlotRenderer slotDrawer) { 1007260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin mRenderer = slotDrawer; 1017260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin if (mRenderer != null) { 1021a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin mRenderer.onSlotSizeChanged(mLayout.mSlotWidth, mLayout.mSlotHeight); 1037260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin mRenderer.onVisibleRangeChanged(getVisibleStart(), getVisibleEnd()); 1047260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin } 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setCenterIndex(int index) { 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int slotCount = mLayout.mSlotCount; 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index < 0 || index >= slotCount) { 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 112d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin Rect rect = mLayout.getSlotRect(index, mTempRect); 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int position = WIDE 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ? (rect.left + rect.right - getWidth()) / 2 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin : (rect.top + rect.bottom - getHeight()) / 2; 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setScrollPosition(position); 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void makeSlotVisible(int index) { 120d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin Rect rect = mLayout.getSlotRect(index, mTempRect); 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int visibleBegin = WIDE ? mScrollX : mScrollY; 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int visibleLength = WIDE ? getWidth() : getHeight(); 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int visibleEnd = visibleBegin + visibleLength; 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int slotBegin = WIDE ? rect.left : rect.top; 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int slotEnd = WIDE ? rect.right : rect.bottom; 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int position = visibleBegin; 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (visibleLength < slotEnd - slotBegin) { 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = visibleBegin; 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (slotBegin < visibleBegin) { 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = slotBegin; 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (slotEnd > visibleEnd) { 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = slotEnd - visibleLength; 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setScrollPosition(position); 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setScrollPosition(int position) { 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = Utils.clamp(position, 0, mLayout.getScrollLimit()); 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller.setPosition(position); 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScrollPosition(position, false); 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1459201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public void setSlotSpec(Spec spec) { 1469201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mLayout.setSlotSpec(spec); 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void addComponent(GLView view) { 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new UnsupportedOperationException(); 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onLayout(boolean changeSize, int l, int t, int r, int b) { 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!changeSize) return; 15777dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 15877dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang // Make sure we are still at a resonable scroll position after the size 15977dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang // is changed (like orientation change). We choose to keep the center 16077dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang // visible slot still visible. This is arbitrary but reasonable. 16177dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int visibleIndex = 16277dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang (mLayout.getVisibleStart() + mLayout.getVisibleEnd()) / 2; 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLayout.setSize(r - l, b - t); 16477dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang makeSlotVisible(visibleIndex); 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mOverscrollEffect == OVERSCROLL_3D) { 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPaper.setSize(r - l, b - t); 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1702341c197b0becf99422e8ad305def77df6161714Owen Lin public void startScatteringAnimation(RelativePosition position) { 1712341c197b0becf99422e8ad305def77df6161714Owen Lin mAnimation = new ScatteringAnimation(position); 1722341c197b0becf99422e8ad305def77df6161714Owen Lin mAnimation.start(); 1732341c197b0becf99422e8ad305def77df6161714Owen Lin if (mLayout.mSlotCount != 0) invalidate(); 1742341c197b0becf99422e8ad305def77df6161714Owen Lin } 1752341c197b0becf99422e8ad305def77df6161714Owen Lin 1762341c197b0becf99422e8ad305def77df6161714Owen Lin public void startRisingAnimation() { 1772341c197b0becf99422e8ad305def77df6161714Owen Lin mAnimation = new RisingAnimation(); 1782341c197b0becf99422e8ad305def77df6161714Owen Lin mAnimation.start(); 1792341c197b0becf99422e8ad305def77df6161714Owen Lin if (mLayout.mSlotCount != 0) invalidate(); 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateScrollPosition(int position, boolean force) { 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!force && (WIDE ? position == mScrollX : position == mScrollY)) return; 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScrollX = position; 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScrollY = position; 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLayout.setScrollPosition(position); 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin onScrollPositionChanged(position); 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onScrollPositionChanged(int newPosition) { 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int limit = mLayout.getScrollLimit(); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onScrollPositionChanged(newPosition, limit); 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Rect getSlotRect(int slotIndex) { 199d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin return mLayout.getSlotRect(slotIndex, new Rect()); 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected boolean onTouch(MotionEvent event) { 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mUIListener != null) mUIListener.onUserInteraction(); 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mGestureDetector.onTouchEvent(event); 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (event.getAction()) { 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MotionEvent.ACTION_DOWN: 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDownInScrolling = !mScroller.isFinished(); 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller.forceFinished(); 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 21177dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang case MotionEvent.ACTION_UP: 21277dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang mPaper.onRelease(); 21377dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang invalidate(); 21477dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang break; 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setListener(Listener listener) { 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener = listener; 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setUserInteractionListener(UserInteractionListener listener) { 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUIListener = listener; 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setOverscrollEffect(int kind) { 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mOverscrollEffect = kind; 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller.setOverfling(kind == OVERSCROLL_SYSTEM); 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2327260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin private static int[] expandIntArray(int array[], int capacity) { 2337260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin while (array.length < capacity) { 2347260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin array = new int[array.length * 2]; 2357260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin } 2367260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin return array; 2377260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin } 2387260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void render(GLCanvas canvas) { 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super.render(canvas); 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2437260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin if (mRenderer == null) return; 2447260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin mRenderer.prepareDrawing(); 2457260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin 2467d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang long animTime = AnimationTime.get(); 2477d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang boolean more = mScroller.advanceAnimation(animTime); 24883f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin more |= mLayout.advanceAnimation(animTime); 24977dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int oldX = mScrollX; 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScrollPosition(mScroller.getPosition(), false); 25177dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 25277dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang boolean paperActive = false; 25377dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang if (mOverscrollEffect == OVERSCROLL_3D) { 25477dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang // Check if an edge is reached and notify mPaper if so. 25577dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int newX = mScrollX; 25677dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int limit = mLayout.getScrollLimit(); 25777dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang if (oldX > 0 && newX == 0 || oldX < limit && newX == limit) { 25877dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang float v = mScroller.getCurrVelocity(); 25977dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang if (newX == limit) v = -v; 260da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang 261da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang // I don't know why, but getCurrVelocity() can return NaN. 262da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang if (!Float.isNaN(v)) { 263da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang mPaper.edgeReached(v); 264da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang } 26577dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang } 26677dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang paperActive = mPaper.advanceAnimation(); 26777dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang } 26877dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 26977dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang more |= paperActive; 27077dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mAnimation != null) { 2727d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang more |= mAnimation.calculate(animTime); 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2757260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin canvas.translate(-mScrollX, -mScrollY); 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2777260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin int requestCount = 0; 2787260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin int requestedSlot[] = expandIntArray(mRequestRenderSlots, 2797260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin mLayout.mVisibleEnd - mLayout.mVisibleStart); 2807260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin 2812341c197b0becf99422e8ad305def77df6161714Owen Lin for (int i = mLayout.mVisibleEnd - 1; i >= mLayout.mVisibleStart; --i) { 2822341c197b0becf99422e8ad305def77df6161714Owen Lin int r = renderItem(canvas, i, 0, paperActive); 2837260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin if ((r & RENDER_MORE_FRAME) != 0) more = true; 2847260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin if ((r & RENDER_MORE_PASS) != 0) requestedSlot[requestCount++] = i; 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2877260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin for (int pass = 1; requestCount != 0; ++pass) { 2887260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin int newCount = 0; 2897260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin for (int i = 0; i < requestCount; ++i) { 2907260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin int r = renderItem(canvas, 2912341c197b0becf99422e8ad305def77df6161714Owen Lin requestedSlot[i], pass, paperActive); 2927260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin if ((r & RENDER_MORE_FRAME) != 0) more = true; 2937260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin if ((r & RENDER_MORE_PASS) != 0) requestedSlot[newCount++] = i; 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 2957260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin requestCount = newCount; 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2987260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin canvas.translate(mScrollX, mScrollY); 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (more) invalidate(); 3018bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin 3028bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin final UserInteractionListener listener = mUIListener; 3038bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin if (mMoreAnimation && !more && listener != null) { 3048bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin mHandler.post(new Runnable() { 3058bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin @Override 3068bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin public void run() { 3078bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin listener.onUserInteractionEnd(); 3088bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin } 3098bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin }); 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMoreAnimation = more; 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 3142341c197b0becf99422e8ad305def77df6161714Owen Lin private int renderItem( 3152341c197b0becf99422e8ad305def77df6161714Owen Lin GLCanvas canvas, int index, int pass, boolean paperActive) { 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.save(GLCanvas.SAVE_FLAG_ALPHA | GLCanvas.SAVE_FLAG_MATRIX); 317d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin Rect rect = mLayout.getSlotRect(index, mTempRect); 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (paperActive) { 3197260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin canvas.multiplyMatrix(mPaper.getTransform(rect, mScrollX), 0); 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 3217260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin canvas.translate(rect.left, rect.top, 0); 322174cac8f92029fc2829c94f274e70793ae948931Chih-Chung Chang } 3232341c197b0becf99422e8ad305def77df6161714Owen Lin if (mAnimation != null && mAnimation.isActive()) { 3242341c197b0becf99422e8ad305def77df6161714Owen Lin mAnimation.apply(canvas, index, rect); 3252341c197b0becf99422e8ad305def77df6161714Owen Lin } 3267260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin int result = mRenderer.renderSlot( 3277260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin canvas, index, pass, rect.right - rect.left, rect.bottom - rect.top); 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.restore(); 3297260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin return result; 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 3322341c197b0becf99422e8ad305def77df6161714Owen Lin public static abstract class SlotAnimation extends Animation { 3332341c197b0becf99422e8ad305def77df6161714Owen Lin protected float mProgress = 0; 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 3352341c197b0becf99422e8ad305def77df6161714Owen Lin public SlotAnimation() { 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setInterpolator(new DecelerateInterpolator(4)); 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setDuration(1500); 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onCalculate(float progress) { 3422341c197b0becf99422e8ad305def77df6161714Owen Lin mProgress = progress; 3432341c197b0becf99422e8ad305def77df6161714Owen Lin } 3442341c197b0becf99422e8ad305def77df6161714Owen Lin 3452341c197b0becf99422e8ad305def77df6161714Owen Lin abstract public void apply(GLCanvas canvas, int slotIndex, Rect target); 3462341c197b0becf99422e8ad305def77df6161714Owen Lin } 3472341c197b0becf99422e8ad305def77df6161714Owen Lin 3482341c197b0becf99422e8ad305def77df6161714Owen Lin public static class RisingAnimation extends SlotAnimation { 3492341c197b0becf99422e8ad305def77df6161714Owen Lin private static final int RISING_DISTANCE = 128; 3502341c197b0becf99422e8ad305def77df6161714Owen Lin 3512341c197b0becf99422e8ad305def77df6161714Owen Lin @Override 3522341c197b0becf99422e8ad305def77df6161714Owen Lin public void apply(GLCanvas canvas, int slotIndex, Rect target) { 3532341c197b0becf99422e8ad305def77df6161714Owen Lin canvas.translate(0, 0, RISING_DISTANCE * (1 - mProgress)); 3542341c197b0becf99422e8ad305def77df6161714Owen Lin } 3552341c197b0becf99422e8ad305def77df6161714Owen Lin } 3562341c197b0becf99422e8ad305def77df6161714Owen Lin 3572341c197b0becf99422e8ad305def77df6161714Owen Lin public static class ScatteringAnimation extends SlotAnimation { 3582341c197b0becf99422e8ad305def77df6161714Owen Lin private int PHOTO_DISTANCE = 1000; 3592341c197b0becf99422e8ad305def77df6161714Owen Lin private RelativePosition mCenter; 3602341c197b0becf99422e8ad305def77df6161714Owen Lin 3612341c197b0becf99422e8ad305def77df6161714Owen Lin public ScatteringAnimation(RelativePosition center) { 3622341c197b0becf99422e8ad305def77df6161714Owen Lin mCenter = center; 3632341c197b0becf99422e8ad305def77df6161714Owen Lin } 3642341c197b0becf99422e8ad305def77df6161714Owen Lin 3652341c197b0becf99422e8ad305def77df6161714Owen Lin @Override 3662341c197b0becf99422e8ad305def77df6161714Owen Lin public void apply(GLCanvas canvas, int slotIndex, Rect target) { 3672341c197b0becf99422e8ad305def77df6161714Owen Lin canvas.translate( 3682341c197b0becf99422e8ad305def77df6161714Owen Lin (mCenter.getX() - target.centerX()) * (1 - mProgress), 3692341c197b0becf99422e8ad305def77df6161714Owen Lin (mCenter.getY() - target.centerY()) * (1 - mProgress), 3702341c197b0becf99422e8ad305def77df6161714Owen Lin slotIndex * PHOTO_DISTANCE * (1 - mProgress)); 3712341c197b0becf99422e8ad305def77df6161714Owen Lin canvas.setAlpha(mProgress); 3722341c197b0becf99422e8ad305def77df6161714Owen Lin } 3732341c197b0becf99422e8ad305def77df6161714Owen Lin } 3742341c197b0becf99422e8ad305def77df6161714Owen Lin 3759201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // This Spec class is used to specify the size of each slot in the SlotView. 3769201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // There are two ways to do it: 3779201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // 3789201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // (1) Specify slotWidth and slotHeight: they specify the width and height 3799201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // of each slot. The number of rows and the gap between slots will be 3809201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // determined automatically. 3819201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // (2) Specify rowsLand, rowsPort, and slotGap: they specify the number 3829201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // of rows in landscape/portrait mode and the gap between slots. The 3839201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // width and height of each slot is determined automatically. 3849201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // 3859201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // The initial value of -1 means they are not specified. 3869201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public static class Spec { 3879201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int slotWidth = -1; 3889201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int slotHeight = -1; 3899201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 3909201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int rowsLand = -1; 3919201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int rowsPort = -1; 3929201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int slotGap = -1; 3939201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 3949201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 3957260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin public class Layout { 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mVisibleStart; 398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mVisibleEnd; 399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSlotCount; 401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSlotWidth; 402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSlotHeight; 4039201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang private int mSlotGap; 4049201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 4059201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang private Spec mSpec; 406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mWidth; 408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mHeight; 409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mUnitCount; 411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentLength; 412f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mScrollPosition; 413f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 41483f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin private IntegerAnimation mVerticalPadding = new IntegerAnimation(); 41583f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin private IntegerAnimation mHorizontalPadding = new IntegerAnimation(); 416f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4179201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public void setSlotSpec(Spec spec) { 4189201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSpec = spec; 419f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 420f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 421f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean setSlotCount(int slotCount) { 42283f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin if (slotCount == mSlotCount) return false; 42383f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin if (mSlotCount != 0) { 42483f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mHorizontalPadding.setEnabled(true); 42583f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mVerticalPadding.setEnabled(true); 42683f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSlotCount = slotCount; 42883f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin int hPadding = mHorizontalPadding.getTarget(); 42983f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin int vPadding = mVerticalPadding.getTarget(); 430f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin initLayoutParameters(); 43183f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin return vPadding != mVerticalPadding.getTarget() 43283f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin || hPadding != mHorizontalPadding.getTarget(); 433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 435d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin public Rect getSlotRect(int index, Rect rect) { 436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int col, row; 437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin col = index / mUnitCount; 439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin row = index - col * mUnitCount; 440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin row = index / mUnitCount; 442f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin col = index - row * mUnitCount; 443f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 444f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 44583f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin int x = mHorizontalPadding.get() + col * (mSlotWidth + mSlotGap); 44683f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin int y = mVerticalPadding.get() + row * (mSlotHeight + mSlotGap); 447d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin rect.set(x, y, x + mSlotWidth, y + mSlotHeight); 448d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin return rect; 449f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 450f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4519201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int getSlotWidth() { 4529201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return mSlotWidth; 4539201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 4549201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 4559201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int getSlotHeight() { 4569201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return mSlotHeight; 4579201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 4589201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 459f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Calculate 460f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // (1) mUnitCount: the number of slots we can fit into one column (or row). 461f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // (2) mContentLength: the width (or height) we need to display all the 462f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // columns (rows). 463f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // (3) padding[]: the vertical and horizontal padding we need in order 464f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // to put the slots towards to the center of the display. 465f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // 466f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The "major" direction is the direction the user can scroll. The other 467f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // direction is the "minor" direction. 468f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // 469f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The comments inside this method are the description when the major 470f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // directon is horizontal (X), and the minor directon is vertical (Y). 471f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void initLayoutParameters( 472f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int majorLength, int minorLength, /* The view width and height */ 473f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int majorUnitSize, int minorUnitSize, /* The slot width and height */ 474f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int[] padding) { 4759201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int unitCount = (minorLength + mSlotGap) / (minorUnitSize + mSlotGap); 476f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (unitCount == 0) unitCount = 1; 477f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUnitCount = unitCount; 478f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 479f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We put extra padding above and below the column. 480f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int availableUnits = Math.min(mUnitCount, mSlotCount); 4819201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int usedMinorLength = availableUnits * minorUnitSize + 4829201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang (availableUnits - 1) * mSlotGap; 4839201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang padding[0] = (minorLength - usedMinorLength) / 2; 484f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 485f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Then calculate how many columns we need for all slots. 486f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int count = ((mSlotCount + mUnitCount - 1) / mUnitCount); 4879201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mContentLength = count * majorUnitSize + (count - 1) * mSlotGap; 488f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 489f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If the content length is less then the screen width, put 490f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // extra padding in left and right. 491f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin padding[1] = Math.max(0, (majorLength - mContentLength) / 2); 492f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 493f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 494f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void initLayoutParameters() { 4959201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // Initialize mSlotWidth and mSlotHeight from mSpec 4969201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang if (mSpec.slotWidth != -1) { 4979201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotGap = 0; 4989201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotWidth = mSpec.slotWidth; 4999201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotHeight = mSpec.slotHeight; 5009201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } else { 5019201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int rows = (mWidth > mHeight) ? mSpec.rowsLand : mSpec.rowsPort; 5029201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotGap = mSpec.slotGap; 5039201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotHeight = Math.max(1, (mHeight - (rows - 1) * mSlotGap) / rows); 5049201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotWidth = mSlotHeight; 5059201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 5069201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 5071a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin if (mRenderer != null) { 5081a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin mRenderer.onSlotSizeChanged(mSlotWidth, mSlotHeight); 5091a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin } 5101a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin 511f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int[] padding = new int[2]; 512f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 513f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin initLayoutParameters(mWidth, mHeight, mSlotWidth, mSlotHeight, padding); 51483f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mVerticalPadding.startAnimateTo(padding[0]); 51583f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mHorizontalPadding.startAnimateTo(padding[1]); 516f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 517f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin initLayoutParameters(mHeight, mWidth, mSlotHeight, mSlotWidth, padding); 51883f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mVerticalPadding.startAnimateTo(padding[1]); 51983f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mHorizontalPadding.startAnimateTo(padding[0]); 520f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 521f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateVisibleSlotRange(); 522f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 523f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 524f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setSize(int width, int height) { 525f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mWidth = width; 526f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHeight = height; 527f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin initLayoutParameters(); 528f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 529f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 530f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateVisibleSlotRange() { 531f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int position = mScrollPosition; 532f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 533f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 5349201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int startCol = position / (mSlotWidth + mSlotGap); 5359201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int start = Math.max(0, mUnitCount * startCol); 5369201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int endCol = (position + mWidth + mSlotWidth + mSlotGap - 1) / 5379201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang (mSlotWidth + mSlotGap); 5389201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int end = Math.min(mSlotCount, mUnitCount * endCol); 539f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setVisibleRange(start, end); 540f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 5419201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int startRow = position / (mSlotHeight + mSlotGap); 5429201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int start = Math.max(0, mUnitCount * startRow); 5439201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int endRow = (position + mHeight + mSlotHeight + mSlotGap - 1) / 5449201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang (mSlotHeight + mSlotGap); 5459201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int end = Math.min(mSlotCount, mUnitCount * endRow); 546f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setVisibleRange(start, end); 547f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 548f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 549f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 550f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setScrollPosition(int position) { 551f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mScrollPosition == position) return; 552f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScrollPosition = position; 553f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateVisibleSlotRange(); 554f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 555f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 556f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void setVisibleRange(int start, int end) { 557f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == mVisibleStart && end == mVisibleEnd) return; 558f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start < end) { 559f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVisibleStart = start; 560f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVisibleEnd = end; 561f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 562f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVisibleStart = mVisibleEnd = 0; 563f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 5647260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin if (mRenderer != null) { 5657260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin mRenderer.onVisibleRangeChanged(mVisibleStart, mVisibleEnd); 5667260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin } 567f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 568f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 569f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getVisibleStart() { 570f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mVisibleStart; 571f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 572f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 573f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getVisibleEnd() { 574f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mVisibleEnd; 575f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 576f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 577f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getSlotIndexByPosition(float x, float y) { 5789201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int absoluteX = Math.round(x) + (WIDE ? mScrollPosition : 0); 5799201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int absoluteY = Math.round(y) + (WIDE ? 0 : mScrollPosition); 5809201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 58183f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin absoluteX -= mHorizontalPadding.get(); 58283f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin absoluteY -= mVerticalPadding.get(); 5839201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 584003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang if (absoluteX < 0 || absoluteY < 0) { 585003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang return INDEX_NONE; 586003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang } 587003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang 5889201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int columnIdx = absoluteX / (mSlotWidth + mSlotGap); 5899201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int rowIdx = absoluteY / (mSlotHeight + mSlotGap); 5909201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 591003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang if (!WIDE && columnIdx >= mUnitCount) { 592f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return INDEX_NONE; 593f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 594f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 595003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang if (WIDE && rowIdx >= mUnitCount) { 596f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return INDEX_NONE; 597f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 5989201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 5999201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang if (absoluteX % (mSlotWidth + mSlotGap) >= mSlotWidth) { 6009201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return INDEX_NONE; 6019201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 6029201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 6039201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang if (absoluteY % (mSlotHeight + mSlotGap) >= mSlotHeight) { 6049201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return INDEX_NONE; 6059201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 6069201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 607f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = WIDE 608f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ? (columnIdx * mUnitCount + rowIdx) 609f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin : (rowIdx * mUnitCount + columnIdx); 610f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 611f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return index >= mSlotCount ? INDEX_NONE : index; 612f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 613f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 614f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getScrollLimit() { 615f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int limit = WIDE ? mContentLength - mWidth : mContentLength - mHeight; 616f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return limit <= 0 ? 0 : limit; 617f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 61883f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin 61983f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin public boolean advanceAnimation(long animTime) { 62083f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin // use '|' to make sure both sides will be executed 62183f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin return mVerticalPadding.calculate(animTime) | mHorizontalPadding.calculate(animTime); 62283f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 623f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 624f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 62548ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin private class MyGestureListener implements GestureDetector.OnGestureListener { 626bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang private boolean isDown; 627bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang 628bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang // We call the listener's onDown() when our onShowPress() is called and 629bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang // call the listener's onUp() when we receive any further event. 630bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang @Override 631bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public void onShowPress(MotionEvent e) { 63248ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin GLRoot root = getGLRoot(); 63348ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin root.lockRenderThread(); 63448ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin try { 63548ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin if (isDown) return; 63648ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); 63748ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin if (index != INDEX_NONE) { 63848ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin isDown = true; 63948ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin mListener.onDown(index); 64048ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin } 64148ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin } finally { 64248ba94ae713dbf57898cfa84ae69517da50cf7a0Owen Lin root.unlockRenderThread(); 643bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang } 644bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang } 645bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang 64690fe70f11b0961e1e5ae353cdf563236a55f502dYuli Huang private void cancelDown(boolean byLongPress) { 647bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang if (!isDown) return; 648bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang isDown = false; 64990fe70f11b0961e1e5ae353cdf563236a55f502dYuli Huang mListener.onUp(byLongPress); 650bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang } 651bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang 652bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang @Override 653bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public boolean onDown(MotionEvent e) { 654bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang return false; 655bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang } 656f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 657f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 658f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onFling(MotionEvent e1, 659f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MotionEvent e2, float velocityX, float velocityY) { 66090fe70f11b0961e1e5ae353cdf563236a55f502dYuli Huang cancelDown(false); 661f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int scrollLimit = mLayout.getScrollLimit(); 662f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (scrollLimit == 0) return false; 663f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float velocity = WIDE ? velocityX : velocityY; 664f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller.fling((int) -velocity, 0, scrollLimit); 665f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mUIListener != null) mUIListener.onUserInteractionBegin(); 666f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin invalidate(); 667f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 668f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 669f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 670f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 671f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onScroll(MotionEvent e1, 672f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MotionEvent e2, float distanceX, float distanceY) { 67390fe70f11b0961e1e5ae353cdf563236a55f502dYuli Huang cancelDown(false); 674f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float distance = WIDE ? distanceX : distanceY; 67577dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int overDistance = mScroller.startScroll( 676f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Math.round(distance), 0, mLayout.getScrollLimit()); 67777dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang if (mOverscrollEffect == OVERSCROLL_3D && overDistance != 0) { 67877dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang mPaper.overScroll(overDistance); 679f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 680f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin invalidate(); 681f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 682f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 683f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 684f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 685f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onSingleTapUp(MotionEvent e) { 68690fe70f11b0961e1e5ae353cdf563236a55f502dYuli Huang cancelDown(false); 687f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mDownInScrolling) return true; 688f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); 689f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index != INDEX_NONE) mListener.onSingleTapUp(index); 690f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 691f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 692f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 693f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 694f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onLongPress(MotionEvent e) { 69590fe70f11b0961e1e5ae353cdf563236a55f502dYuli Huang cancelDown(true); 696f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mDownInScrolling) return; 697f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin lockRendering(); 698f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 699f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); 700f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index != INDEX_NONE) mListener.onLongTap(index); 701f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } finally { 702f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin unlockRendering(); 703f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 704f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 705f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 706f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 707f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setStartIndex(int index) { 708f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mStartIndex = index; 709f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 710f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 711f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Return true if the layout parameters have been changed 712f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean setSlotCount(int slotCount) { 713f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean changed = mLayout.setSlotCount(slotCount); 714f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 715f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // mStartIndex is applied the first time setSlotCount is called. 716f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mStartIndex != INDEX_NONE) { 717f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setCenterIndex(mStartIndex); 718f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mStartIndex = INDEX_NONE; 719f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 720189e21a31f1c520b2802f734a53a37e5f3b455f4Yuli Huang // Reset the scroll position to avoid scrolling over the updated limit. 721189e21a31f1c520b2802f734a53a37e5f3b455f4Yuli Huang setScrollPosition(WIDE ? mScrollX : mScrollY); 722f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return changed; 723f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 724f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 725f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getVisibleStart() { 726f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mLayout.getVisibleStart(); 727f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 728f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 729f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getVisibleEnd() { 730f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mLayout.getVisibleEnd(); 731f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 732f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 733f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getScrollX() { 734f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mScrollX; 735f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 736f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 737f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getScrollY() { 738f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mScrollY; 739f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 74083f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin 74183f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin private static class IntegerAnimation extends Animation { 74283f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin private int mTarget; 74383f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin private int mCurrent = 0; 74483f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin private int mFrom = 0; 74583f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin private boolean mEnabled = false; 74683f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin 74783f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin public void setEnabled(boolean enabled) { 74883f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mEnabled = enabled; 74983f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 75083f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin 75183f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin public void startAnimateTo(int target) { 75283f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin if (!mEnabled) { 75383f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mTarget = mCurrent = target; 75483f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin return; 75583f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 75683f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin if (target == mTarget) return; 75783f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin 75883f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mFrom = mCurrent; 75983f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mTarget = target; 76083f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin setDuration(180); 76183f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin start(); 76283f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 76383f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin 76483f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin public int get() { 76583f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin return mCurrent; 76683f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 76783f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin 76883f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin public int getTarget() { 76983f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin return mTarget; 77083f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 77183f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin 77283f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin @Override 77383f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin protected void onCalculate(float progress) { 77483f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin mCurrent = Math.round(mFrom + progress * (mTarget - mFrom)); 77583f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin if (progress == 1f) mEnabled = false; 77683f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 77783f88ad1c72ae24acc5e78efc93c1e09e1c70c97Owen Lin } 778f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 779