PagedView.java revision 28750fba6a2d141eb9a1e566718c17236030b815
1321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung/* 2321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Copyright (C) 2010 The Android Open Source Project 3321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * 4321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Licensed under the Apache License, Version 2.0 (the "License"); 5321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * you may not use this file except in compliance with the License. 6321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * You may obtain a copy of the License at 7321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * 8321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * http://www.apache.org/licenses/LICENSE-2.0 9321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * 10321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Unless required by applicable law or agreed to in writing, software 11321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * distributed under the License is distributed on an "AS IS" BASIS, 12321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * See the License for the specific language governing permissions and 14321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * limitations under the License. 15321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 16321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 17321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungpackage com.android.launcher2; 18321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 19e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chungimport java.util.ArrayList; 20e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chungimport java.util.HashMap; 219f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy 22321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.content.Context; 23241c3b451d7841ba08247beea784953eca4e8582Winson Chungimport android.graphics.Bitmap; 24321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.graphics.Canvas; 25321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.graphics.Rect; 26321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.os.Parcel; 27321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.os.Parcelable; 28321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.util.AttributeSet; 29e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chungimport android.util.Log; 305f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chungimport android.view.ActionMode; 31321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.view.MotionEvent; 32321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.view.VelocityTracker; 33321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.view.View; 34321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.view.ViewConfiguration; 35321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.view.ViewGroup; 36321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.view.ViewParent; 3780baf5a6b3c62a62265f626d43d1167783c94131Winson Chungimport android.view.animation.Animation; 385f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.view.animation.Animation.AnimationListener; 39e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chungimport android.view.animation.AnimationUtils; 405f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chungimport android.widget.Checkable; 41e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chungimport android.widget.LinearLayout; 42321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungimport android.widget.Scroller; 43321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 44e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chungimport com.android.launcher.R; 4580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung 46321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung/** 47321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * An abstraction of the original Workspace which supports browsing through a 480142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * sequential list of "pages" 49321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 50321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chungpublic abstract class PagedView extends ViewGroup { 51321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private static final String TAG = "PagedView"; 520142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected static final int INVALID_PAGE = -1; 53321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 5486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung // the min drag distance for a fling to register, to prevent random page shifts 55321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private static final int MIN_LENGTH_FOR_FLING = 50; 56321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 575f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung private static final int PAGE_SNAP_ANIMATION_DURATION = 1000; 580142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected static final float NANOTIME_DIV = 1000000000.0f; 590142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 600142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // the velocity at which a fling gesture will cause us to snap to the next page 610142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected int mSnapVelocity = 500; 620142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected float mSmoothingTime; 640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected float mTouchX; 65321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected boolean mFirstLayout = true; 670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 680142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected int mCurrentPage; 690142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected int mNextPage = INVALID_PAGE; 700142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected Scroller mScroller; 71321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private VelocityTracker mVelocityTracker; 72321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 73321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private float mDownMotionX; 74321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private float mLastMotionX; 75321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private float mLastMotionY; 76321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected final static int TOUCH_STATE_REST = 0; 780142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected final static int TOUCH_STATE_SCROLLING = 1; 790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected final static int TOUCH_STATE_PREV_PAGE = 2; 800142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected final static int TOUCH_STATE_NEXT_PAGE = 3; 81321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 820142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected int mTouchState = TOUCH_STATE_REST; 83321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected OnLongClickListener mLongClickListener; 85321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 86321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private boolean mAllowLongPress = true; 87321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 88321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private int mTouchSlop; 89321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private int mPagingTouchSlop; 90321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private int mMaximumVelocity; 91321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 925f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka protected static final int INVALID_POINTER = -1; 93321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 945f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka protected int mActivePointerId = INVALID_POINTER; 95321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 9686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung private PageSwitchListener mPageSwitchListener; 97321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 9886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung private ArrayList<Boolean> mDirtyPageContent; 9986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung private boolean mDirtyPageAlpha; 100321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1015f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung // choice modes 1025f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected static final int CHOICE_MODE_NONE = 0; 1035f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected static final int CHOICE_MODE_SINGLE = 1; 1045f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung // Multiple selection mode is not supported by all Launcher actions atm 1055f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected static final int CHOICE_MODE_MULTIPLE = 2; 1069f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy 1075f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung private int mChoiceMode; 1085f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung private ActionMode mActionMode; 1095f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 110241c3b451d7841ba08247beea784953eca4e8582Winson Chung protected PagedViewIconCache mPageViewIconCache; 111241c3b451d7841ba08247beea784953eca4e8582Winson Chung 1120142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // If true, syncPages and syncPageItems will be called to refresh pages 1130142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected boolean mContentIsRefreshable = true; 1140142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // If true, modify alpha of neighboring pages as user scrolls left/right 1160142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected boolean mFadeInAdjacentScreens = true; 1170142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1180142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding 1190142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // to switch to a new page 1200142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected boolean mUsePagingTouchSlop = true; 1210142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // If true, the subclass should directly update mScrollX itself in its computeScroll method 1230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // (SmoothPagedView does this) 1240142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected boolean mDeferScrollUpdate = false; 1250142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 126241c3b451d7841ba08247beea784953eca4e8582Winson Chung /** 127241c3b451d7841ba08247beea784953eca4e8582Winson Chung * Simple cache mechanism for PagedViewIcon outlines. 128241c3b451d7841ba08247beea784953eca4e8582Winson Chung */ 129241c3b451d7841ba08247beea784953eca4e8582Winson Chung class PagedViewIconCache { 130241c3b451d7841ba08247beea784953eca4e8582Winson Chung private final HashMap<Object, Bitmap> iconOutlineCache = new HashMap<Object, Bitmap>(); 131241c3b451d7841ba08247beea784953eca4e8582Winson Chung 132241c3b451d7841ba08247beea784953eca4e8582Winson Chung public void clear() { 133241c3b451d7841ba08247beea784953eca4e8582Winson Chung iconOutlineCache.clear(); 134241c3b451d7841ba08247beea784953eca4e8582Winson Chung } 135241c3b451d7841ba08247beea784953eca4e8582Winson Chung public void addOutline(Object key, Bitmap b) { 136241c3b451d7841ba08247beea784953eca4e8582Winson Chung iconOutlineCache.put(key, b); 137241c3b451d7841ba08247beea784953eca4e8582Winson Chung } 138241c3b451d7841ba08247beea784953eca4e8582Winson Chung public void removeOutline(Object key) { 139241c3b451d7841ba08247beea784953eca4e8582Winson Chung if (iconOutlineCache.containsKey(key)) { 140241c3b451d7841ba08247beea784953eca4e8582Winson Chung iconOutlineCache.remove(key); 141241c3b451d7841ba08247beea784953eca4e8582Winson Chung } 142241c3b451d7841ba08247beea784953eca4e8582Winson Chung } 143241c3b451d7841ba08247beea784953eca4e8582Winson Chung public Bitmap getOutline(Object key) { 144241c3b451d7841ba08247beea784953eca4e8582Winson Chung return iconOutlineCache.get(key); 145241c3b451d7841ba08247beea784953eca4e8582Winson Chung } 146241c3b451d7841ba08247beea784953eca4e8582Winson Chung } 147241c3b451d7841ba08247beea784953eca4e8582Winson Chung 14886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung public interface PageSwitchListener { 14986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung void onPageSwitch(View newPage, int newPageIndex); 150321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 151321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1520142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public interface PageMovingListener { 1530142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka void onPageBeginMoving(); 1540142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka void onPageEndMoving(); 1550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1560142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 157321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public PagedView(Context context) { 158321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung this(context, null); 159321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 160321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 161321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public PagedView(Context context, AttributeSet attrs) { 162321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung this(context, attrs, 0); 163321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 164321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 165321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public PagedView(Context context, AttributeSet attrs, int defStyle) { 166321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super(context, attrs, defStyle); 1675f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mChoiceMode = CHOICE_MODE_NONE; 168321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 169321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung setHapticFeedbackEnabled(false); 1700142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka init(); 171321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 172321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 173321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 174321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Initializes various states for this workspace. 175321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 1760142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void init() { 17786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mDirtyPageContent = new ArrayList<Boolean>(); 17886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mDirtyPageContent.ensureCapacity(32); 179241c3b451d7841ba08247beea784953eca4e8582Winson Chung mPageViewIconCache = new PagedViewIconCache(); 180321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mScroller = new Scroller(getContext()); 18186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mCurrentPage = 0; 182321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 183321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final ViewConfiguration configuration = ViewConfiguration.get(getContext()); 184321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchSlop = configuration.getScaledTouchSlop(); 185321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mPagingTouchSlop = configuration.getScaledPagingTouchSlop(); 186321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 187321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 188321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 18986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung public void setPageSwitchListener(PageSwitchListener pageSwitchListener) { 19086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mPageSwitchListener = pageSwitchListener; 19186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mPageSwitchListener != null) { 19286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage); 193321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 194321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 195321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 196321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 19786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * Returns the index of the currently displayed page. 198321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * 19986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * @return The index of the currently displayed page. 200321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 20186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int getCurrentPage() { 20286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung return mCurrentPage; 203321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 204321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 20586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int getPageCount() { 206321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return getChildCount(); 207321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 208321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 20986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung View getPageAt(int index) { 210321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return getChildAt(index); 211321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 212321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 213321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int getScrollWidth() { 214321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return getWidth(); 215321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 216321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 217321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 21886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * Sets the current page. 219321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 22086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung void setCurrentPage(int currentPage) { 221321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (!mScroller.isFinished()) mScroller.abortAnimation(); 222321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (getChildCount() == 0) return; 223321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 22486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1)); 22586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung scrollTo(getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage), 0); 22680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung 227321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung invalidate(); 22886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung notifyPageSwitchListener(); 229321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 230321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 2310142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void notifyPageSwitchListener() { 23286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mPageSwitchListener != null) { 23386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage); 234321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 235321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 236321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 2370142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // a method that subclasses can override to add behavior 2380142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void pageBeginMoving() { 2390142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 2400142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 2410142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // a method that subclasses can override to add behavior 2420142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void pageEndMoving() { 2430142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 2440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 245321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 24686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * Registers the specified listener on each page contained in this workspace. 247321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * 248321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * @param l The listener used to respond to long clicks. 249321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 250321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 251321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void setOnLongClickListener(OnLongClickListener l) { 252321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLongClickListener = l; 25386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung final int count = getPageCount(); 254321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < count; i++) { 25586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung getPageAt(i).setOnLongClickListener(l); 256321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 257321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 258321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 259321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 2600142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void scrollTo(int x, int y) { 2610142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka super.scrollTo(x, y); 2620142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTouchX = x; 2630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mSmoothingTime = System.nanoTime() / NANOTIME_DIV; 2640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 2650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 2660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // we moved this functionality to a helper function so SmoothPagedView can reuse it 2670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected boolean computeScrollHelper() { 268321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mScroller.computeScrollOffset()) { 2695f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka mDirtyPageAlpha = true; 270321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 2710142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka invalidate(); 2720142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka return true; 27386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung } else if (mNextPage != INVALID_PAGE) { 2745f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka mDirtyPageAlpha = true; 27586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1)); 27686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mNextPage = INVALID_PAGE; 2770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka notifyPageSwitchListener(); 2780142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageEndMoving(); 2790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka return true; 280321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 2810142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka return false; 2820142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 2830142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 2840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka @Override 2850142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void computeScroll() { 2860142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka computeScrollHelper(); 287321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 288321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 289321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 290321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 291321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 292321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 293321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (widthMode != MeasureSpec.EXACTLY) { 294321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung throw new IllegalStateException("Workspace can only be used in EXACTLY mode."); 295321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 296321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 297321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 298321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int heightSize = MeasureSpec.getSize(heightMeasureSpec); 299321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (heightMode != MeasureSpec.EXACTLY) { 300321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung throw new IllegalStateException("Workspace can only be used in EXACTLY mode."); 301321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 302321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 303321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // The children are given the same width and height as the workspace 3045f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka // unless they were set to WRAP_CONTENT 305321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int childCount = getChildCount(); 306321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < childCount; i++) { 3075f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka // disallowing padding in paged view (just pass 0) 3085f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka final View child = getChildAt(i); 3095f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 3105f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 3115f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka int childWidthMode; 3125f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka if (lp.width == LayoutParams.WRAP_CONTENT) { 3135f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka childWidthMode = MeasureSpec.AT_MOST; 3145f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } else { 3155f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka childWidthMode = MeasureSpec.EXACTLY; 3165f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 3175f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 3185f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka int childHeightMode; 3195f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka if (lp.height == LayoutParams.WRAP_CONTENT) { 3205f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka childHeightMode = MeasureSpec.AT_MOST; 3215f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } else { 3225f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka childHeightMode = MeasureSpec.EXACTLY; 3235f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 3245f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 3255f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka final int childWidthMeasureSpec = 3265f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka MeasureSpec.makeMeasureSpec(widthSize, childWidthMode); 3275f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka final int childHeightMeasureSpec = 3285f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka MeasureSpec.makeMeasureSpec(heightSize, childHeightMode); 3295f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 3305f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 331321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 332321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 333321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung setMeasuredDimension(widthSize, heightSize); 334cfc629446ca86366665263dba6520a7b978b7c3eMichael Jurka } 335321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 336cfc629446ca86366665263dba6520a7b978b7c3eMichael Jurka @Override 33728750fba6a2d141eb9a1e566718c17236030b815Michael Jurka protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 3385f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) { 339321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung setHorizontalScrollBarEnabled(false); 340cfc629446ca86366665263dba6520a7b978b7c3eMichael Jurka int newX = getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage); 341cfc629446ca86366665263dba6520a7b978b7c3eMichael Jurka scrollTo(newX, 0); 342cfc629446ca86366665263dba6520a7b978b7c3eMichael Jurka mScroller.setFinalX(newX); 343321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung setHorizontalScrollBarEnabled(true); 344321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mFirstLayout = false; 345321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 346321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 347321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int childCount = getChildCount(); 348321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int childLeft = 0; 349321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (childCount > 0) { 350e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung childLeft = getRelativeChildOffset(0); 351321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 352321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 353321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < childCount; i++) { 354321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final View child = getChildAt(i); 355321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (child.getVisibility() != View.GONE) { 356321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int childWidth = child.getMeasuredWidth(); 3575f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka final int childHeight = (getMeasuredHeight() - child.getMeasuredHeight()) / 2; 3585f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka child.layout(childLeft, childHeight, 3595f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka childLeft + childWidth, childHeight + child.getMeasuredHeight()); 360321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung childLeft += childWidth; 361321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 362321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 363321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 364321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 365e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected void updateAdjacentPagesAlpha() { 3660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mFadeInAdjacentScreens) { 3670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) { 368e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int halfScreenSize = getMeasuredWidth() / 2; 369e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int screenCenter = mScrollX + halfScreenSize; 370e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung 3710142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = getChildCount(); 3720142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < childCount; ++i) { 3730142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka View layout = (View) getChildAt(i); 3740142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka int childWidth = layout.getMeasuredWidth(); 3750142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka int halfChildWidth = (childWidth / 2); 3760142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka int childCenter = getChildOffset(i) + halfChildWidth; 377e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung 378e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung int d = halfChildWidth; 379e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung int distanceFromScreenCenter = childCenter - screenCenter; 380e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung if (distanceFromScreenCenter > 0) { 381e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung if (i > 0) { 382e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung d += getChildAt(i - 1).getMeasuredWidth() / 2; 383e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung } 3840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 385e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung if (i < childCount - 1) { 386e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung d += getChildAt(i + 1).getMeasuredWidth() / 2; 387e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung } 3880142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 389e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung 390e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung float dimAlpha = (float) (Math.abs(distanceFromScreenCenter)) / d; 391e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung dimAlpha = Math.max(0.0f, Math.min(1.0f, (dimAlpha * dimAlpha))); 392e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung float alpha = 1.0f - dimAlpha; 393e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung 3940142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (Float.compare(alpha, layout.getAlpha()) != 0) { 3950142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka layout.setAlpha(alpha); 3960142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 397affd7b4d23cecb4ed74133dd8bd9a5ede099c562Winson Chung } 3980142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageAlpha = false; 399321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 400321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 401e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 4020142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 403e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung @Override 404e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected void dispatchDraw(Canvas canvas) { 405e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung updateAdjacentPagesAlpha(); 4060142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 407e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung // Find out which screens are visible; as an optimization we only call draw on them 4080142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // As an optimization, this code assumes that all pages have the same width as the 0th 4090142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // page. 4100142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int pageCount = getChildCount(); 411c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka if (pageCount > 0) { 412c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka final int pageWidth = getChildAt(0).getMeasuredWidth(); 413c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka final int screenWidth = getMeasuredWidth(); 414c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka int x = getRelativeChildOffset(0) + pageWidth; 415c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka int leftScreen = 0; 416c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka int rightScreen = 0; 417c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka while (x <= mScrollX) { 418c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka leftScreen++; 419c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka x += pageWidth; 420c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // replace above line with this if you don't assume all pages have same width as 0th 421c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // page: 422c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // x += getChildAt(leftScreen).getMeasuredWidth(); 423c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka } 424c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka rightScreen = leftScreen; 425c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka while (x < mScrollX + screenWidth) { 426c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka rightScreen++; 427c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka x += pageWidth; 428c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // replace above line with this if you don't assume all pages have same width as 0th 429c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // page: 430c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka //if (rightScreen < pageCount) { 431c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // x += getChildAt(rightScreen).getMeasuredWidth(); 432c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka //} 433c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka } 434c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka rightScreen = Math.min(getChildCount() - 1, rightScreen); 4350142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 436c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka final long drawingTime = getDrawingTime(); 437c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka for (int i = leftScreen; i <= rightScreen; i++) { 438c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka drawChild(canvas, getChildAt(i), drawingTime); 439c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka } 4400142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 441321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 442321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 443321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 444321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { 44586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int page = indexOfChild(child); 44686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (page != mCurrentPage || !mScroller.isFinished()) { 44786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(page); 448321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 449321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 450321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return false; 451321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 452321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 453321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 454321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 45586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int focusablePage; 45686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mNextPage != INVALID_PAGE) { 45786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung focusablePage = mNextPage; 458321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 45986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung focusablePage = mCurrentPage; 460321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 46186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung View v = getPageAt(focusablePage); 462321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (v != null) { 463321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung v.requestFocus(direction, previouslyFocusedRect); 464321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 465321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return false; 466321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 467321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 468321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 469321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean dispatchUnhandledMove(View focused, int direction) { 470321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (direction == View.FOCUS_LEFT) { 47186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (getCurrentPage() > 0) { 47286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(getCurrentPage() - 1); 473321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 474321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 475321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (direction == View.FOCUS_RIGHT) { 47686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (getCurrentPage() < getPageCount() - 1) { 47786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(getCurrentPage() + 1); 478321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 479321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 480321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 481321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return super.dispatchUnhandledMove(focused, direction); 482321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 483321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 484321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 485321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 48686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) { 48786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung getPageAt(mCurrentPage).addFocusables(views, direction); 488321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 489321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (direction == View.FOCUS_LEFT) { 49086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage > 0) { 49186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung getPageAt(mCurrentPage - 1).addFocusables(views, direction); 492321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 493321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (direction == View.FOCUS_RIGHT){ 49486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage < getPageCount() - 1) { 49586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung getPageAt(mCurrentPage + 1).addFocusables(views, direction); 496321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 497321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 498321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 499321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 500321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 501321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * If one of our descendant views decides that it could be focused now, only 50286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * pass that along if it's on the current page. 503321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * 50486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * This happens when live folders requery, and if they're off page, they 50586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * end up calling requestFocus, which pulls it on page. 506321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 507321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 508321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void focusableViewAvailable(View focused) { 50986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung View current = getPageAt(mCurrentPage); 510321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung View v = focused; 511321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung while (true) { 512321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (v == current) { 513321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.focusableViewAvailable(focused); 514321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return; 515321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 516321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (v == this) { 517321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return; 518321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 519321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung ViewParent parent = v.getParent(); 520321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (parent instanceof View) { 521321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung v = (View)v.getParent(); 522321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 523321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return; 524321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 525321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 526321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 527321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 528321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 529321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * {@inheritDoc} 530321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 531321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 532321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 533321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (disallowIntercept) { 534321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // We need to make sure to cancel our long press if 535321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // a scrollable widget takes over touch events 53686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung final View currentPage = getChildAt(mCurrentPage); 53786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung currentPage.cancelLongPress(); 538321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 539321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.requestDisallowInterceptTouchEvent(disallowIntercept); 540321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 541321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 542321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 543321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean onInterceptTouchEvent(MotionEvent ev) { 544321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 545321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * This method JUST determines whether we want to intercept the motion. 546321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * If we return true, onTouchEvent will be called and we do the actual 547321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * scrolling there. 548321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 549321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 550321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 551321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Shortcut the most recurring case: the user is in the dragging 552321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * state and he is moving his finger. We want to intercept this 553321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * motion. 554321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 555321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int action = ev.getAction(); 556321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if ((action == MotionEvent.ACTION_MOVE) && 557321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung (mTouchState == TOUCH_STATE_SCROLLING)) { 558321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 559321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 560321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 561321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung switch (action & MotionEvent.ACTION_MASK) { 562321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_MOVE: { 563321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 564321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 565321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * whether the user has moved far enough from his original down touch. 566321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 5671ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka if (mActivePointerId != INVALID_POINTER) { 5681ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka determineScrollingStart(ev); 5691ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka break; 5701ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka } 5711ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN 5721ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // event. in that case, treat the first occurence of a move event as a ACTION_DOWN 5731ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // i.e. fall through to the next case (don't break) 5741ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events 5751ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // while it's small- this was causing a crash before we checked for INVALID_POINTER) 576321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 577321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 578321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_DOWN: { 579321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float x = ev.getX(); 580321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float y = ev.getY(); 581321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Remember location of down touch 582321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mDownMotionX = x; 583321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionX = x; 584321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionY = y; 585321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = ev.getPointerId(0); 586321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mAllowLongPress = true; 587321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 588321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 589321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * If being flinged and user touches the screen, initiate drag; 590321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * otherwise don't. mScroller.isFinished should be false when 591321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * being flinged. 592321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 5935f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final int xDist = (mScroller.getFinalX() - mScroller.getCurrX()); 5945f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop); 5955f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung if (finishedScrolling) { 5965f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mTouchState = TOUCH_STATE_REST; 5975f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mScroller.abortAnimation(); 5985f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } else { 5995f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mTouchState = TOUCH_STATE_SCROLLING; 6005f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 601321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 60286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung // check if this can be the beginning of a tap on the side of the pages 603321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // to scroll the current page 604321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if ((mTouchState != TOUCH_STATE_PREV_PAGE) && 605321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung (mTouchState != TOUCH_STATE_NEXT_PAGE)) { 606321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (getChildCount() > 0) { 607e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int width = getMeasuredWidth(); 608e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int offset = getRelativeChildOffset(mCurrentPage); 609e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung if (x < offset) { 610321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_PREV_PAGE; 611e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } else if (x > (width - offset)) { 612321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_NEXT_PAGE; 613321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 614321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 615321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 616321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 617321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 618321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 619321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_CANCEL: 620321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_UP: 621321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Release the drag 6220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageEndMoving(); 623321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_REST; 624321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mAllowLongPress = false; 625321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = INVALID_POINTER; 626321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 627321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 628321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 629321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_POINTER_UP: 630321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung onSecondaryPointerUp(ev); 631321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 632321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 633321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 634321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 635321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * The only time we want to intercept motion events is if we are in the 636321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * drag mode. 637321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 638321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return mTouchState != TOUCH_STATE_REST; 639321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 640321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 64180baf5a6b3c62a62265f626d43d1167783c94131Winson Chung protected void animateClickFeedback(View v, final Runnable r) { 64280baf5a6b3c62a62265f626d43d1167783c94131Winson Chung // animate the view slightly to show click feedback running some logic after it is "pressed" 64380baf5a6b3c62a62265f626d43d1167783c94131Winson Chung Animation anim = AnimationUtils.loadAnimation(getContext(), 64480baf5a6b3c62a62265f626d43d1167783c94131Winson Chung R.anim.paged_view_click_feedback); 64580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung anim.setAnimationListener(new AnimationListener() { 64680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung @Override 64780baf5a6b3c62a62265f626d43d1167783c94131Winson Chung public void onAnimationStart(Animation animation) {} 64880baf5a6b3c62a62265f626d43d1167783c94131Winson Chung @Override 64980baf5a6b3c62a62265f626d43d1167783c94131Winson Chung public void onAnimationRepeat(Animation animation) { 65080baf5a6b3c62a62265f626d43d1167783c94131Winson Chung r.run(); 65180baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 65280baf5a6b3c62a62265f626d43d1167783c94131Winson Chung @Override 65380baf5a6b3c62a62265f626d43d1167783c94131Winson Chung public void onAnimationEnd(Animation animation) {} 65480baf5a6b3c62a62265f626d43d1167783c94131Winson Chung }); 65580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung v.startAnimation(anim); 65680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 65780baf5a6b3c62a62265f626d43d1167783c94131Winson Chung 658321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 659321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Determines if we should change the touch state to start scrolling after the 660321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * user moves their touch point too far. 661321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 662321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private void determineScrollingStart(MotionEvent ev) { 663321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 664321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Locally do absolute value. mLastMotionX is set to the y value 665321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * of the down event. 666321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 667321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerIndex = ev.findPointerIndex(mActivePointerId); 668321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float x = ev.getX(pointerIndex); 669321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float y = ev.getY(pointerIndex); 670321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int xDiff = (int) Math.abs(x - mLastMotionX); 671321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int yDiff = (int) Math.abs(y - mLastMotionY); 672321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 673321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int touchSlop = mTouchSlop; 674321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung boolean xPaged = xDiff > mPagingTouchSlop; 675321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung boolean xMoved = xDiff > touchSlop; 676321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung boolean yMoved = yDiff > touchSlop; 677321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 678321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (xMoved || yMoved) { 6790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mUsePagingTouchSlop ? xPaged : xMoved) { 680321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Scroll if the user moved far enough along the X axis 681321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_SCROLLING; 682321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionX = x; 6830142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTouchX = mScrollX; 6840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mSmoothingTime = System.nanoTime() / NANOTIME_DIV; 6850142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageBeginMoving(); 686321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 687321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Either way, cancel any pending longpress 688321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mAllowLongPress) { 689321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mAllowLongPress = false; 690321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Try canceling the long press. It could also have been scheduled 691321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // by a distant descendant, so use the mAllowLongPress flag to block 692321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // everything 69386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung final View currentPage = getPageAt(mCurrentPage); 69486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung currentPage.cancelLongPress(); 695321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 696321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 697321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 698321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 699321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 700321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean onTouchEvent(MotionEvent ev) { 701321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mVelocityTracker == null) { 702321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker = VelocityTracker.obtain(); 703321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 704321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker.addMovement(ev); 705321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 706321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int action = ev.getAction(); 707321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 708321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung switch (action & MotionEvent.ACTION_MASK) { 709321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_DOWN: 710321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 711321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * If being flinged and user touches, stop the fling. isFinished 712321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * will be false if being flinged. 713321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 714321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (!mScroller.isFinished()) { 715321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mScroller.abortAnimation(); 716321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 717321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 718321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Remember where the motion event started 719321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mDownMotionX = mLastMotionX = ev.getX(); 720321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = ev.getPointerId(0); 7210142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mTouchState == TOUCH_STATE_SCROLLING) { 7220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageBeginMoving(); 7230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 724321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 725321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 726321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_MOVE: 727321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mTouchState == TOUCH_STATE_SCROLLING) { 728321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Scroll to follow the motion event 729321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerIndex = ev.findPointerIndex(mActivePointerId); 730321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float x = ev.getX(pointerIndex); 731321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int deltaX = (int) (mLastMotionX - x); 732321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionX = x; 733321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 734321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int sx = getScrollX(); 735321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (deltaX < 0) { 736321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (sx > 0) { 7370142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTouchX += Math.max(-mTouchX, deltaX); 7380142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mSmoothingTime = System.nanoTime() / NANOTIME_DIV; 7390142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (!mDeferScrollUpdate) { 7400142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka scrollBy(Math.max(-sx, deltaX), 0); 7410142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 7420142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // This will trigger a call to computeScroll() on next drawChild() call 7430142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka invalidate(); 7440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 745321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 746321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (deltaX > 0) { 747321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int lastChildIndex = getChildCount() - 1; 748321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int availableToScroll = getChildOffset(lastChildIndex) - 749321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung getRelativeChildOffset(lastChildIndex) - sx; 750321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (availableToScroll > 0) { 7510142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTouchX += Math.min(availableToScroll, deltaX); 7520142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mSmoothingTime = System.nanoTime() / NANOTIME_DIV; 7530142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (!mDeferScrollUpdate) { 7540142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka scrollBy(Math.min(availableToScroll, deltaX), 0); 7550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 7560142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // This will trigger a call to computeScroll() on next drawChild() call 7570142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka invalidate(); 7580142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 759321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 760321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 761321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung awakenScrollBars(); 762321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 763321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if ((mTouchState == TOUCH_STATE_PREV_PAGE) || 764321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung (mTouchState == TOUCH_STATE_NEXT_PAGE)) { 765321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung determineScrollingStart(ev); 766321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 767321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 768321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 769321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_UP: 770321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mTouchState == TOUCH_STATE_SCROLLING) { 771321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int activePointerId = mActivePointerId; 772321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerIndex = ev.findPointerIndex(activePointerId); 773321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float x = ev.getX(pointerIndex); 774321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final VelocityTracker velocityTracker = mVelocityTracker; 775321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 776321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int velocityX = (int) velocityTracker.getXVelocity(activePointerId); 777321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung boolean isfling = Math.abs(mDownMotionX - x) > MIN_LENGTH_FOR_FLING; 778321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 7790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int snapVelocity = mSnapVelocity; 7800142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (isfling && velocityX > snapVelocity && mCurrentPage > 0) { 7810142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPageWithVelocity(mCurrentPage - 1, velocityX); 7820142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else if (isfling && velocityX < -snapVelocity && 78386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mCurrentPage < getChildCount() - 1) { 7840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPageWithVelocity(mCurrentPage + 1, velocityX); 785321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 786321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung snapToDestination(); 787321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 788321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 789321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mVelocityTracker != null) { 790321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker.recycle(); 791321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker = null; 792321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 793321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (mTouchState == TOUCH_STATE_PREV_PAGE) { 794321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // at this point we have not moved beyond the touch slop 795321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so 796321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // we can just page 79786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int nextPage = Math.max(0, mCurrentPage - 1); 79886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (nextPage != mCurrentPage) { 79986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(nextPage); 800321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 801321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung snapToDestination(); 802321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 803321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) { 804321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // at this point we have not moved beyond the touch slop 805321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so 806321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // we can just page 80786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1); 80886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (nextPage != mCurrentPage) { 80986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(nextPage); 810321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 811321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung snapToDestination(); 812321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 813321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 814321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_REST; 815321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = INVALID_POINTER; 816321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 817321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 818321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_CANCEL: 819321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_REST; 820321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = INVALID_POINTER; 821321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 822321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 823321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_POINTER_UP: 824321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung onSecondaryPointerUp(ev); 825321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 826321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 827321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 828321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 829321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 830321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 831321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private void onSecondaryPointerUp(MotionEvent ev) { 832321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> 833321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung MotionEvent.ACTION_POINTER_INDEX_SHIFT; 834321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerId = ev.getPointerId(pointerIndex); 835321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (pointerId == mActivePointerId) { 836321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // This was our active pointer going up. Choose a new 837321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // active pointer and adjust accordingly. 838321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // TODO: Make this decision more intelligent. 839321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 840321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionX = mDownMotionX = ev.getX(newPointerIndex); 841321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionY = ev.getY(newPointerIndex); 842321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = ev.getPointerId(newPointerIndex); 843321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mVelocityTracker != null) { 844321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker.clear(); 845321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 846321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 847321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 848321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 849321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 850321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void requestChildFocus(View child, View focused) { 851321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.requestChildFocus(child, focused); 85286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int page = indexOfChild(child); 85386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (page >= 0 && !isInTouchMode()) { 85486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(page); 855321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 856321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 857321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 858e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected int getChildIndexForRelativeOffset(int relativeOffset) { 859e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung final int childCount = getChildCount(); 860e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int left = getRelativeChildOffset(0); 861e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung for (int i = 0; i < childCount; ++i) { 862e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung final int right = (left + getChildAt(i).getMeasuredWidth()); 863e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung if (left <= relativeOffset && relativeOffset <= right) { 864e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung return i; 865e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 866e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung left = right; 867e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 868e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung return -1; 869e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 870e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung 871321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected int getRelativeChildOffset(int index) { 872321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return (getMeasuredWidth() - getChildAt(index).getMeasuredWidth()) / 2; 873321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 874321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 875321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected int getChildOffset(int index) { 876321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (getChildCount() == 0) 877321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return 0; 878321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 879321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int offset = getRelativeChildOffset(0); 880321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < index; ++i) { 881321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung offset += getChildAt(i).getMeasuredWidth(); 882321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 883321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return offset; 884321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 885321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 886d19d3ca3ec22aeec48b8e555e9764b98ff8cae5fAdam Cohen int getPageNearestToCenterOfScreen() { 887321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int minDistanceFromScreenCenter = getMeasuredWidth(); 888321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int minDistanceFromScreenCenterIndex = -1; 889321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int screenCenter = mScrollX + (getMeasuredWidth() / 2); 890321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int childCount = getChildCount(); 891321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < childCount; ++i) { 8920142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka View layout = (View) getChildAt(i); 893321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int childWidth = layout.getMeasuredWidth(); 894321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int halfChildWidth = (childWidth / 2); 895321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int childCenter = getChildOffset(i) + halfChildWidth; 896321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int distanceFromScreenCenter = Math.abs(childCenter - screenCenter); 897321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (distanceFromScreenCenter < minDistanceFromScreenCenter) { 898321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung minDistanceFromScreenCenter = distanceFromScreenCenter; 899321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung minDistanceFromScreenCenterIndex = i; 900321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 901321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 902d19d3ca3ec22aeec48b8e555e9764b98ff8cae5fAdam Cohen return minDistanceFromScreenCenterIndex; 903d19d3ca3ec22aeec48b8e555e9764b98ff8cae5fAdam Cohen } 904d19d3ca3ec22aeec48b8e555e9764b98ff8cae5fAdam Cohen 905d19d3ca3ec22aeec48b8e555e9764b98ff8cae5fAdam Cohen protected void snapToDestination() { 906d19d3ca3ec22aeec48b8e555e9764b98ff8cae5fAdam Cohen snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION); 907321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 908321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 9090142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPageWithVelocity(int whichPage, int velocity) { 9100142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // We ignore velocity in this implementation, but children (e.g. SmoothPagedView) 9110142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // can use it 9120142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPage(whichPage); 9130142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 9140142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPage(int whichPage) { 9165f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); 917321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 918321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 9190142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPage(int whichPage, int duration) { 92086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1)); 921321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 92286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage); 923321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int sX = getScrollX(); 924321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int delta = newX - sX; 9250142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPage(whichPage, delta, duration); 9260142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 9270142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9280142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPage(int whichPage, int delta, int duration) { 9290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mNextPage = whichPage; 9300142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9310142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka View focusedChild = getFocusedChild(); 9320142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (focusedChild != null && whichPage != mCurrentPage && 9330142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka focusedChild == getChildAt(mCurrentPage)) { 9340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka focusedChild.clearFocus(); 9350142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 9360142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9370142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageBeginMoving(); 938321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung awakenScrollBars(duration); 939321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (duration == 0) { 940321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung duration = Math.abs(delta); 941321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 942321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 943321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (!mScroller.isFinished()) mScroller.abortAnimation(); 9440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mScroller.startScroll(getScrollX(), 0, delta, 0, duration); 94580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung 94680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung // only load some associated pages 94786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung loadAssociatedPages(mNextPage); 9480142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka notifyPageSwitchListener(); 949321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung invalidate(); 950321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 951321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 952321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 953321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected Parcelable onSaveInstanceState() { 954321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final SavedState state = new SavedState(super.onSaveInstanceState()); 95586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung state.currentPage = mCurrentPage; 956321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return state; 957321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 958321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 959321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 960321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected void onRestoreInstanceState(Parcelable state) { 961321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung SavedState savedState = (SavedState) state; 962321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.onRestoreInstanceState(savedState.getSuperState()); 96386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (savedState.currentPage != -1) { 96486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mCurrentPage = savedState.currentPage; 965321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 966321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 967321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 968321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void scrollLeft() { 969321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mScroller.isFinished()) { 97086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage > 0) snapToPage(mCurrentPage - 1); 971321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 97286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mNextPage > 0) snapToPage(mNextPage - 1); 973321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 974321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 975321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 976321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void scrollRight() { 977321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mScroller.isFinished()) { 97886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1); 979321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 98086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1); 981321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 982321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 983321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 98486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung public int getPageForView(View v) { 985321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int result = -1; 986321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (v != null) { 987321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung ViewParent vp = v.getParent(); 988321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int count = getChildCount(); 989321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < count; i++) { 990321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (vp == getChildAt(i)) { 991321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return i; 992321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 993321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 994321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 995321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return result; 996321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 997321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 998321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 999321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * @return True is long presses are still allowed for the current touch 1000321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 1001321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean allowLongPress() { 1002321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return mAllowLongPress; 1003321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1004321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 10050142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka /** 10060142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Set true to allow long-press events to be triggered, usually checked by 10070142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * {@link Launcher} to accept or block dpad-initiated long-presses. 10080142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka */ 10090142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void setAllowLongPress(boolean allowLongPress) { 10100142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mAllowLongPress = allowLongPress; 10110142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 10120142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1013321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public static class SavedState extends BaseSavedState { 101486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int currentPage = -1; 1015321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1016321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung SavedState(Parcelable superState) { 1017321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super(superState); 1018321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1019321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1020321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private SavedState(Parcel in) { 1021321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super(in); 102286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung currentPage = in.readInt(); 1023321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1024321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1025321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 1026321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void writeToParcel(Parcel out, int flags) { 1027321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.writeToParcel(out, flags); 102886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung out.writeInt(currentPage); 1029321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1030321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1031321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public static final Parcelable.Creator<SavedState> CREATOR = 1032321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung new Parcelable.Creator<SavedState>() { 1033321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public SavedState createFromParcel(Parcel in) { 1034321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return new SavedState(in); 1035321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1036321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1037321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public SavedState[] newArray(int size) { 1038321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return new SavedState[size]; 1039321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1040321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung }; 1041321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1042321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 104386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung public void loadAssociatedPages(int page) { 10440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mContentIsRefreshable) { 10450142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int count = getChildCount(); 10460142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (page < count) { 1047e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int lowerPageBound = getAssociatedLowerPageBound(page); 1048e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int upperPageBound = getAssociatedUpperPageBound(page); 10490142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < count; ++i) { 10500142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final ViewGroup layout = (ViewGroup) getChildAt(i); 10510142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = layout.getChildCount(); 10520142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (lowerPageBound <= i && i <= upperPageBound) { 10530142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mDirtyPageContent.get(i)) { 10540142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka syncPageItems(i); 10550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageContent.set(i, false); 10560142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 10570142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 10580142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (childCount > 0) { 10590142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka layout.removeAllViews(); 10600142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 10610142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageContent.set(i, true); 106280baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 106380baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 106480baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 106580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 106680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 106780baf5a6b3c62a62265f626d43d1167783c94131Winson Chung 1068e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected int getAssociatedLowerPageBound(int page) { 1069e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung return Math.max(0, page - 1); 1070e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 1071e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected int getAssociatedUpperPageBound(int page) { 1072e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung final int count = getChildCount(); 1073e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung return Math.min(page + 1, count - 1); 1074e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 1075e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung 10765f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected void startChoiceMode(int mode, ActionMode.Callback callback) { 1077430c53bc80be01996b45e55687885d6c05314645Patrick Dubroy if (isChoiceMode(CHOICE_MODE_NONE)) { 1078430c53bc80be01996b45e55687885d6c05314645Patrick Dubroy mChoiceMode = mode; 1079430c53bc80be01996b45e55687885d6c05314645Patrick Dubroy mActionMode = startActionMode(callback); 1080430c53bc80be01996b45e55687885d6c05314645Patrick Dubroy } 10815f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10825f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 10832b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy public void endChoiceMode() { 10845f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung if (!isChoiceMode(CHOICE_MODE_NONE)) { 10855f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mChoiceMode = CHOICE_MODE_NONE; 10865f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung resetCheckedGrandchildren(); 10879f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy mActionMode.finish(); 10889f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy mActionMode = null; 10895f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10905f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10915f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 10925f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected boolean isChoiceMode(int mode) { 10935f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung return mChoiceMode == mode; 10945f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10955f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 10965f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected ArrayList<Checkable> getCheckedGrandchildren() { 10975f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung ArrayList<Checkable> checked = new ArrayList<Checkable>(); 10985f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final int childCount = getChildCount(); 10995f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung for (int i = 0; i < childCount; ++i) { 11005f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i); 11015f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final int grandChildCount = layout.getChildCount(); 11025f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung for (int j = 0; j < grandChildCount; ++j) { 11035f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final View v = layout.getChildAt(j); 11049f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy if (v instanceof Checkable && ((Checkable) v).isChecked()) { 11055f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung checked.add((Checkable) v); 11065f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11075f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11085f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11095f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung return checked; 11105f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11115f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 11129f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy /** 11139f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy * If in CHOICE_MODE_SINGLE and an item is checked, returns that item. 11149f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy * Otherwise, returns null. 11159f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy */ 11169f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy protected Checkable getSingleCheckedGrandchild() { 11179f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy if (mChoiceMode == CHOICE_MODE_SINGLE) { 11189f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy final int childCount = getChildCount(); 11199f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy for (int i = 0; i < childCount; ++i) { 11209f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i); 11219f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy final int grandChildCount = layout.getChildCount(); 11229f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy for (int j = 0; j < grandChildCount; ++j) { 11239f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy final View v = layout.getChildAt(j); 11249f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy if (v instanceof Checkable && ((Checkable) v).isChecked()) { 11259f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy return (Checkable) v; 11269f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11279f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11289f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11299f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11309f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy return null; 11319f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11329f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy 11332b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy public Object getChosenItem() { 11342b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy View checkedView = (View) getSingleCheckedGrandchild(); 11352b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy if (checkedView != null) { 11362b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy return checkedView.getTag(); 11372b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy } 11382b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy return null; 11392b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy } 11402b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy 11415f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected void resetCheckedGrandchildren() { 11425f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung // loop through children, and set all of their children to _not_ be checked 11435f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final ArrayList<Checkable> checked = getCheckedGrandchildren(); 11445f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung for (int i = 0; i < checked.size(); ++i) { 11455f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final Checkable c = checked.get(i); 11465f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung c.setChecked(false); 11475f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11485f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11495f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 115086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung /** 115186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * This method is called ONLY to synchronize the number of pages that the paged view has. 115286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * To actually fill the pages with information, implement syncPageItems() below. It is 115386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * guaranteed that syncPageItems() will be called for a particular page before it is shown, 115486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * and therefore, individual page items do not need to be updated in this method. 115586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung */ 1156321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public abstract void syncPages(); 115786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 115886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung /** 115986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * This method is called to synchronize the items that are on a particular page. If views on 116086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * the page can be reused, then they should be updated within this method. 116186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung */ 1162321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public abstract void syncPageItems(int page); 116386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 1164321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void invalidatePageData() { 11650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mContentIsRefreshable) { 11660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // Update all the pages 11670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka syncPages(); 116886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 11690142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // Mark each of the pages as dirty 11700142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int count = getChildCount(); 11710142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageContent.clear(); 11720142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < count; ++i) { 11730142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageContent.add(true); 11740142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 117586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 11760142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // Load any pages that are necessary for the current window of views 11770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka loadAssociatedPages(mCurrentPage); 11780142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageAlpha = true; 11790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka requestLayout(); 11800142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1181321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1182321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung} 1183