PagedView.java revision e3193b93ad7bf33e2e45319084a99b9fc986622b
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 337cfc629446ca86366665263dba6520a7b978b7c3eMichael 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; 3770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka int distanceFromScreenCenter = Math.abs(childCenter - screenCenter); 3780142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka float alpha = 0.0f; 3790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (distanceFromScreenCenter < halfChildWidth) { 3800142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka alpha = 1.0f; 3810142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else if (distanceFromScreenCenter > childWidth) { 3820142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka alpha = 0.0f; 3830142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 3840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka float dimAlpha = (float) (distanceFromScreenCenter - halfChildWidth) / halfChildWidth; 3850142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka dimAlpha = Math.max(0.0f, Math.min(1.0f, (dimAlpha * dimAlpha))); 3860142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka alpha = 1.0f - dimAlpha; 3870142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 3880142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (Float.compare(alpha, layout.getAlpha()) != 0) { 3890142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka layout.setAlpha(alpha); 3900142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 391affd7b4d23cecb4ed74133dd8bd9a5ede099c562Winson Chung } 3920142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageAlpha = false; 393321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 394321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 395e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 3960142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 397e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung @Override 398e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected void dispatchDraw(Canvas canvas) { 399e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung updateAdjacentPagesAlpha(); 4000142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 401e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung // Find out which screens are visible; as an optimization we only call draw on them 4020142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // As an optimization, this code assumes that all pages have the same width as the 0th 4030142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // page. 4040142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int pageCount = getChildCount(); 405c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka if (pageCount > 0) { 406c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka final int pageWidth = getChildAt(0).getMeasuredWidth(); 407c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka final int screenWidth = getMeasuredWidth(); 408c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka int x = getRelativeChildOffset(0) + pageWidth; 409c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka int leftScreen = 0; 410c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka int rightScreen = 0; 411c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka while (x <= mScrollX) { 412c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka leftScreen++; 413c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka x += pageWidth; 414c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // replace above line with this if you don't assume all pages have same width as 0th 415c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // page: 416c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // x += getChildAt(leftScreen).getMeasuredWidth(); 417c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka } 418c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka rightScreen = leftScreen; 419c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka while (x < mScrollX + screenWidth) { 420c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka rightScreen++; 421c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka x += pageWidth; 422c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // replace above line with this if you don't assume all pages have same width as 0th 423c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // page: 424c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka //if (rightScreen < pageCount) { 425c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka // x += getChildAt(rightScreen).getMeasuredWidth(); 426c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka //} 427c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka } 428c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka rightScreen = Math.min(getChildCount() - 1, rightScreen); 4290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 430c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka final long drawingTime = getDrawingTime(); 431c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka for (int i = leftScreen; i <= rightScreen; i++) { 432c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka drawChild(canvas, getChildAt(i), drawingTime); 433c4fb9173e73c0092a089512734c0d7df13189014Michael Jurka } 4340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 435321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 436321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 437321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 438321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { 43986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int page = indexOfChild(child); 44086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (page != mCurrentPage || !mScroller.isFinished()) { 44186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(page); 442321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 443321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 444321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return false; 445321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 446321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 447321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 448321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 44986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int focusablePage; 45086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mNextPage != INVALID_PAGE) { 45186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung focusablePage = mNextPage; 452321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 45386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung focusablePage = mCurrentPage; 454321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 45586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung View v = getPageAt(focusablePage); 456321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (v != null) { 457321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung v.requestFocus(direction, previouslyFocusedRect); 458321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 459321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return false; 460321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 461321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 462321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 463321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean dispatchUnhandledMove(View focused, int direction) { 464321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (direction == View.FOCUS_LEFT) { 46586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (getCurrentPage() > 0) { 46686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(getCurrentPage() - 1); 467321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 468321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 469321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (direction == View.FOCUS_RIGHT) { 47086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (getCurrentPage() < getPageCount() - 1) { 47186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(getCurrentPage() + 1); 472321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 473321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 474321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 475321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return super.dispatchUnhandledMove(focused, direction); 476321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 477321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 478321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 479321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 48086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) { 48186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung getPageAt(mCurrentPage).addFocusables(views, direction); 482321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 483321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (direction == View.FOCUS_LEFT) { 48486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage > 0) { 48586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung getPageAt(mCurrentPage - 1).addFocusables(views, direction); 486321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 487321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (direction == View.FOCUS_RIGHT){ 48886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage < getPageCount() - 1) { 48986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung getPageAt(mCurrentPage + 1).addFocusables(views, direction); 490321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 491321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 492321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 493321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 494321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 495321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * If one of our descendant views decides that it could be focused now, only 49686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * pass that along if it's on the current page. 497321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * 49886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * This happens when live folders requery, and if they're off page, they 49986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * end up calling requestFocus, which pulls it on page. 500321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 501321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 502321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void focusableViewAvailable(View focused) { 50386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung View current = getPageAt(mCurrentPage); 504321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung View v = focused; 505321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung while (true) { 506321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (v == current) { 507321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.focusableViewAvailable(focused); 508321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return; 509321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 510321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (v == this) { 511321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return; 512321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 513321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung ViewParent parent = v.getParent(); 514321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (parent instanceof View) { 515321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung v = (View)v.getParent(); 516321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 517321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return; 518321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 519321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 520321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 521321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 522321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 523321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * {@inheritDoc} 524321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 525321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 526321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 527321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (disallowIntercept) { 528321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // We need to make sure to cancel our long press if 529321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // a scrollable widget takes over touch events 53086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung final View currentPage = getChildAt(mCurrentPage); 53186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung currentPage.cancelLongPress(); 532321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 533321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.requestDisallowInterceptTouchEvent(disallowIntercept); 534321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 535321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 536321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 537321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean onInterceptTouchEvent(MotionEvent ev) { 538321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 539321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * This method JUST determines whether we want to intercept the motion. 540321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * If we return true, onTouchEvent will be called and we do the actual 541321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * scrolling there. 542321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 543321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 544321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 545321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Shortcut the most recurring case: the user is in the dragging 546321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * state and he is moving his finger. We want to intercept this 547321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * motion. 548321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 549321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int action = ev.getAction(); 550321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if ((action == MotionEvent.ACTION_MOVE) && 551321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung (mTouchState == TOUCH_STATE_SCROLLING)) { 552321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 553321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 554321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 555321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung switch (action & MotionEvent.ACTION_MASK) { 556321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_MOVE: { 557321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 558321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check 559321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * whether the user has moved far enough from his original down touch. 560321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 5611ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka if (mActivePointerId != INVALID_POINTER) { 5621ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka determineScrollingStart(ev); 5631ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka break; 5641ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka } 5651ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN 5661ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // event. in that case, treat the first occurence of a move event as a ACTION_DOWN 5671ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // i.e. fall through to the next case (don't break) 5681ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events 5691ff706b8c03063740ca74868fea46fa47d71bb27Michael Jurka // while it's small- this was causing a crash before we checked for INVALID_POINTER) 570321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 571321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 572321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_DOWN: { 573321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float x = ev.getX(); 574321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float y = ev.getY(); 575321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Remember location of down touch 576321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mDownMotionX = x; 577321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionX = x; 578321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionY = y; 579321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = ev.getPointerId(0); 580321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mAllowLongPress = true; 581321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 582321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 583321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * If being flinged and user touches the screen, initiate drag; 584321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * otherwise don't. mScroller.isFinished should be false when 585321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * being flinged. 586321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 5875f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final int xDist = (mScroller.getFinalX() - mScroller.getCurrX()); 5885f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop); 5895f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung if (finishedScrolling) { 5905f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mTouchState = TOUCH_STATE_REST; 5915f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mScroller.abortAnimation(); 5925f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } else { 5935f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mTouchState = TOUCH_STATE_SCROLLING; 5945f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 595321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 59686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung // check if this can be the beginning of a tap on the side of the pages 597321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // to scroll the current page 598321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if ((mTouchState != TOUCH_STATE_PREV_PAGE) && 599321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung (mTouchState != TOUCH_STATE_NEXT_PAGE)) { 600321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (getChildCount() > 0) { 601e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int width = getMeasuredWidth(); 602e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int offset = getRelativeChildOffset(mCurrentPage); 603e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung if (x < offset) { 604321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_PREV_PAGE; 605e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } else if (x > (width - offset)) { 606321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_NEXT_PAGE; 607321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 608321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 609321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 610321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 611321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 612321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 613321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_CANCEL: 614321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_UP: 615321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Release the drag 6160142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageEndMoving(); 617321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_REST; 618321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mAllowLongPress = false; 619321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = INVALID_POINTER; 620321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 621321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 622321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 623321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_POINTER_UP: 624321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung onSecondaryPointerUp(ev); 625321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 626321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 627321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 628321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 629321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * The only time we want to intercept motion events is if we are in the 630321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * drag mode. 631321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 632321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return mTouchState != TOUCH_STATE_REST; 633321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 634321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 63580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung protected void animateClickFeedback(View v, final Runnable r) { 63680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung // animate the view slightly to show click feedback running some logic after it is "pressed" 63780baf5a6b3c62a62265f626d43d1167783c94131Winson Chung Animation anim = AnimationUtils.loadAnimation(getContext(), 63880baf5a6b3c62a62265f626d43d1167783c94131Winson Chung R.anim.paged_view_click_feedback); 63980baf5a6b3c62a62265f626d43d1167783c94131Winson Chung anim.setAnimationListener(new AnimationListener() { 64080baf5a6b3c62a62265f626d43d1167783c94131Winson Chung @Override 64180baf5a6b3c62a62265f626d43d1167783c94131Winson Chung public void onAnimationStart(Animation animation) {} 64280baf5a6b3c62a62265f626d43d1167783c94131Winson Chung @Override 64380baf5a6b3c62a62265f626d43d1167783c94131Winson Chung public void onAnimationRepeat(Animation animation) { 64480baf5a6b3c62a62265f626d43d1167783c94131Winson Chung r.run(); 64580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 64680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung @Override 64780baf5a6b3c62a62265f626d43d1167783c94131Winson Chung public void onAnimationEnd(Animation animation) {} 64880baf5a6b3c62a62265f626d43d1167783c94131Winson Chung }); 64980baf5a6b3c62a62265f626d43d1167783c94131Winson Chung v.startAnimation(anim); 65080baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 65180baf5a6b3c62a62265f626d43d1167783c94131Winson Chung 652321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 653321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Determines if we should change the touch state to start scrolling after the 654321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * user moves their touch point too far. 655321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 656321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private void determineScrollingStart(MotionEvent ev) { 657321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 658321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * Locally do absolute value. mLastMotionX is set to the y value 659321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * of the down event. 660321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 661321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerIndex = ev.findPointerIndex(mActivePointerId); 662321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float x = ev.getX(pointerIndex); 663321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float y = ev.getY(pointerIndex); 664321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int xDiff = (int) Math.abs(x - mLastMotionX); 665321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int yDiff = (int) Math.abs(y - mLastMotionY); 666321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 667321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int touchSlop = mTouchSlop; 668321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung boolean xPaged = xDiff > mPagingTouchSlop; 669321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung boolean xMoved = xDiff > touchSlop; 670321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung boolean yMoved = yDiff > touchSlop; 671321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 672321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (xMoved || yMoved) { 6730142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mUsePagingTouchSlop ? xPaged : xMoved) { 674321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Scroll if the user moved far enough along the X axis 675321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_SCROLLING; 676321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionX = x; 6770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTouchX = mScrollX; 6780142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mSmoothingTime = System.nanoTime() / NANOTIME_DIV; 6790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageBeginMoving(); 680321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 681321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Either way, cancel any pending longpress 682321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mAllowLongPress) { 683321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mAllowLongPress = false; 684321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Try canceling the long press. It could also have been scheduled 685321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // by a distant descendant, so use the mAllowLongPress flag to block 686321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // everything 68786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung final View currentPage = getPageAt(mCurrentPage); 68886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung currentPage.cancelLongPress(); 689321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 690321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 691321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 692321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 693321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 694321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean onTouchEvent(MotionEvent ev) { 695321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mVelocityTracker == null) { 696321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker = VelocityTracker.obtain(); 697321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 698321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker.addMovement(ev); 699321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 700321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int action = ev.getAction(); 701321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 702321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung switch (action & MotionEvent.ACTION_MASK) { 703321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_DOWN: 704321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /* 705321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * If being flinged and user touches, stop the fling. isFinished 706321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * will be false if being flinged. 707321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 708321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (!mScroller.isFinished()) { 709321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mScroller.abortAnimation(); 710321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 711321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 712321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Remember where the motion event started 713321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mDownMotionX = mLastMotionX = ev.getX(); 714321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = ev.getPointerId(0); 7150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mTouchState == TOUCH_STATE_SCROLLING) { 7160142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageBeginMoving(); 7170142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 718321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 719321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 720321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_MOVE: 721321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mTouchState == TOUCH_STATE_SCROLLING) { 722321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // Scroll to follow the motion event 723321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerIndex = ev.findPointerIndex(mActivePointerId); 724321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float x = ev.getX(pointerIndex); 725321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int deltaX = (int) (mLastMotionX - x); 726321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionX = x; 727321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 728321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int sx = getScrollX(); 729321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (deltaX < 0) { 730321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (sx > 0) { 7310142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTouchX += Math.max(-mTouchX, deltaX); 7320142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mSmoothingTime = System.nanoTime() / NANOTIME_DIV; 7330142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (!mDeferScrollUpdate) { 7340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka scrollBy(Math.max(-sx, deltaX), 0); 7350142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 7360142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // This will trigger a call to computeScroll() on next drawChild() call 7370142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka invalidate(); 7380142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 739321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 740321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (deltaX > 0) { 741321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int lastChildIndex = getChildCount() - 1; 742321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int availableToScroll = getChildOffset(lastChildIndex) - 743321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung getRelativeChildOffset(lastChildIndex) - sx; 744321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (availableToScroll > 0) { 7450142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTouchX += Math.min(availableToScroll, deltaX); 7460142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mSmoothingTime = System.nanoTime() / NANOTIME_DIV; 7470142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (!mDeferScrollUpdate) { 7480142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka scrollBy(Math.min(availableToScroll, deltaX), 0); 7490142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 7500142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // This will trigger a call to computeScroll() on next drawChild() call 7510142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka invalidate(); 7520142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 753321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 754321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 755321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung awakenScrollBars(); 756321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 757321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if ((mTouchState == TOUCH_STATE_PREV_PAGE) || 758321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung (mTouchState == TOUCH_STATE_NEXT_PAGE)) { 759321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung determineScrollingStart(ev); 760321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 761321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 762321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 763321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_UP: 764321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mTouchState == TOUCH_STATE_SCROLLING) { 765321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int activePointerId = mActivePointerId; 766321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerIndex = ev.findPointerIndex(activePointerId); 767321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final float x = ev.getX(pointerIndex); 768321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final VelocityTracker velocityTracker = mVelocityTracker; 769321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 770321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int velocityX = (int) velocityTracker.getXVelocity(activePointerId); 771321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung boolean isfling = Math.abs(mDownMotionX - x) > MIN_LENGTH_FOR_FLING; 772321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 7730142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int snapVelocity = mSnapVelocity; 7740142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (isfling && velocityX > snapVelocity && mCurrentPage > 0) { 7750142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPageWithVelocity(mCurrentPage - 1, velocityX); 7760142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else if (isfling && velocityX < -snapVelocity && 77786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mCurrentPage < getChildCount() - 1) { 7780142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPageWithVelocity(mCurrentPage + 1, velocityX); 779321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 780321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung snapToDestination(); 781321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 782321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 783321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mVelocityTracker != null) { 784321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker.recycle(); 785321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker = null; 786321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 787321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (mTouchState == TOUCH_STATE_PREV_PAGE) { 788321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // at this point we have not moved beyond the touch slop 789321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so 790321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // we can just page 79186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int nextPage = Math.max(0, mCurrentPage - 1); 79286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (nextPage != mCurrentPage) { 79386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(nextPage); 794321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 795321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung snapToDestination(); 796321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 797321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) { 798321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // at this point we have not moved beyond the touch slop 799321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so 800321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // we can just page 80186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1); 80286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (nextPage != mCurrentPage) { 80386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(nextPage); 804321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 805321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung snapToDestination(); 806321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 807321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 808321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_REST; 809321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = INVALID_POINTER; 810321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 811321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 812321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_CANCEL: 813321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mTouchState = TOUCH_STATE_REST; 814321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = INVALID_POINTER; 815321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 816321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 817321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung case MotionEvent.ACTION_POINTER_UP: 818321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung onSecondaryPointerUp(ev); 819321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung break; 820321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 821321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 822321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return true; 823321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 824321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 825321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private void onSecondaryPointerUp(MotionEvent ev) { 826321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> 827321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung MotionEvent.ACTION_POINTER_INDEX_SHIFT; 828321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int pointerId = ev.getPointerId(pointerIndex); 829321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (pointerId == mActivePointerId) { 830321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // This was our active pointer going up. Choose a new 831321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // active pointer and adjust accordingly. 832321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung // TODO: Make this decision more intelligent. 833321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 834321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionX = mDownMotionX = ev.getX(newPointerIndex); 835321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mLastMotionY = ev.getY(newPointerIndex); 836321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mActivePointerId = ev.getPointerId(newPointerIndex); 837321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mVelocityTracker != null) { 838321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung mVelocityTracker.clear(); 839321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 840321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 841321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 842321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 843321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 844321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void requestChildFocus(View child, View focused) { 845321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.requestChildFocus(child, focused); 84686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int page = indexOfChild(child); 84786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (page >= 0 && !isInTouchMode()) { 84886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung snapToPage(page); 849321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 850321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 851321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 852e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected int getChildIndexForRelativeOffset(int relativeOffset) { 853e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung final int childCount = getChildCount(); 854e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int left = getRelativeChildOffset(0); 855e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung for (int i = 0; i < childCount; ++i) { 856e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung final int right = (left + getChildAt(i).getMeasuredWidth()); 857e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung if (left <= relativeOffset && relativeOffset <= right) { 858e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung return i; 859e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 860e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung left = right; 861e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 862e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung return -1; 863e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 864e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung 865321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected int getRelativeChildOffset(int index) { 866321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return (getMeasuredWidth() - getChildAt(index).getMeasuredWidth()) / 2; 867321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 868321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 869321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected int getChildOffset(int index) { 870321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (getChildCount() == 0) 871321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return 0; 872321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 873321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int offset = getRelativeChildOffset(0); 874321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < index; ++i) { 875321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung offset += getChildAt(i).getMeasuredWidth(); 876321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 877321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return offset; 878321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 879321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 880321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected void snapToDestination() { 881321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int minDistanceFromScreenCenter = getMeasuredWidth(); 882321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int minDistanceFromScreenCenterIndex = -1; 883321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int screenCenter = mScrollX + (getMeasuredWidth() / 2); 884321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int childCount = getChildCount(); 885321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < childCount; ++i) { 8860142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka View layout = (View) getChildAt(i); 887321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int childWidth = layout.getMeasuredWidth(); 888321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int halfChildWidth = (childWidth / 2); 889321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int childCenter = getChildOffset(i) + halfChildWidth; 890321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int distanceFromScreenCenter = Math.abs(childCenter - screenCenter); 891321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (distanceFromScreenCenter < minDistanceFromScreenCenter) { 892321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung minDistanceFromScreenCenter = distanceFromScreenCenter; 893321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung minDistanceFromScreenCenterIndex = i; 894321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 895321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 8965f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung snapToPage(minDistanceFromScreenCenterIndex, PAGE_SNAP_ANIMATION_DURATION); 897321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 898321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 8990142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPageWithVelocity(int whichPage, int velocity) { 9000142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // We ignore velocity in this implementation, but children (e.g. SmoothPagedView) 9010142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // can use it 9020142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPage(whichPage); 9030142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 9040142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9050142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPage(int whichPage) { 9065f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); 907321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 908321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 9090142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPage(int whichPage, int duration) { 91086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1)); 911321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 91286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage); 913321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int sX = getScrollX(); 914321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final int delta = newX - sX; 9150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPage(whichPage, delta, duration); 9160142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 9170142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9180142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPage(int whichPage, int delta, int duration) { 9190142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mNextPage = whichPage; 9200142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9210142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka View focusedChild = getFocusedChild(); 9220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (focusedChild != null && whichPage != mCurrentPage && 9230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka focusedChild == getChildAt(mCurrentPage)) { 9240142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka focusedChild.clearFocus(); 9250142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 9260142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9270142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka pageBeginMoving(); 928321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung awakenScrollBars(duration); 929321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (duration == 0) { 930321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung duration = Math.abs(delta); 931321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 932321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 933321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (!mScroller.isFinished()) mScroller.abortAnimation(); 9340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mScroller.startScroll(getScrollX(), 0, delta, 0, duration); 93580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung 93680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung // only load some associated pages 93786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung loadAssociatedPages(mNextPage); 9380142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka notifyPageSwitchListener(); 939321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung invalidate(); 940321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 941321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 942321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 943321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected Parcelable onSaveInstanceState() { 944321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung final SavedState state = new SavedState(super.onSaveInstanceState()); 94586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung state.currentPage = mCurrentPage; 946321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return state; 947321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 948321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 949321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 950321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung protected void onRestoreInstanceState(Parcelable state) { 951321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung SavedState savedState = (SavedState) state; 952321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.onRestoreInstanceState(savedState.getSuperState()); 95386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (savedState.currentPage != -1) { 95486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung mCurrentPage = savedState.currentPage; 955321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 956321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 957321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 958321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void scrollLeft() { 959321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mScroller.isFinished()) { 96086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage > 0) snapToPage(mCurrentPage - 1); 961321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 96286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mNextPage > 0) snapToPage(mNextPage - 1); 963321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 964321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 965321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 966321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void scrollRight() { 967321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (mScroller.isFinished()) { 96886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1); 969321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } else { 97086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1); 971321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 972321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 973321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 97486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung public int getPageForView(View v) { 975321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int result = -1; 976321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (v != null) { 977321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung ViewParent vp = v.getParent(); 978321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung int count = getChildCount(); 979321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung for (int i = 0; i < count; i++) { 980321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung if (vp == getChildAt(i)) { 981321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return i; 982321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 983321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 984321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 985321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return result; 986321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 987321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 988321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung /** 989321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung * @return True is long presses are still allowed for the current touch 990321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung */ 991321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public boolean allowLongPress() { 992321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return mAllowLongPress; 993321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 994321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 9950142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka /** 9960142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Set true to allow long-press events to be triggered, usually checked by 9970142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * {@link Launcher} to accept or block dpad-initiated long-presses. 9980142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka */ 9990142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void setAllowLongPress(boolean allowLongPress) { 10000142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mAllowLongPress = allowLongPress; 10010142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 10020142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1003321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public static class SavedState extends BaseSavedState { 100486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int currentPage = -1; 1005321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1006321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung SavedState(Parcelable superState) { 1007321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super(superState); 1008321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1009321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1010321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung private SavedState(Parcel in) { 1011321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super(in); 101286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung currentPage = in.readInt(); 1013321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1014321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1015321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung @Override 1016321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void writeToParcel(Parcel out, int flags) { 1017321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung super.writeToParcel(out, flags); 101886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung out.writeInt(currentPage); 1019321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1020321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1021321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public static final Parcelable.Creator<SavedState> CREATOR = 1022321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung new Parcelable.Creator<SavedState>() { 1023321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public SavedState createFromParcel(Parcel in) { 1024321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return new SavedState(in); 1025321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1026321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 1027321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public SavedState[] newArray(int size) { 1028321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung return new SavedState[size]; 1029321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1030321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung }; 1031321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1032321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung 103386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung public void loadAssociatedPages(int page) { 10340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mContentIsRefreshable) { 10350142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int count = getChildCount(); 10360142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (page < count) { 1037e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int lowerPageBound = getAssociatedLowerPageBound(page); 1038e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung int upperPageBound = getAssociatedUpperPageBound(page); 10390142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < count; ++i) { 10400142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final ViewGroup layout = (ViewGroup) getChildAt(i); 10410142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = layout.getChildCount(); 10420142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (lowerPageBound <= i && i <= upperPageBound) { 10430142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mDirtyPageContent.get(i)) { 10440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka syncPageItems(i); 10450142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageContent.set(i, false); 10460142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 10470142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 10480142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (childCount > 0) { 10490142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka layout.removeAllViews(); 10500142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 10510142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageContent.set(i, true); 105280baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 105380baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 105480baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 105580baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 105680baf5a6b3c62a62265f626d43d1167783c94131Winson Chung } 105780baf5a6b3c62a62265f626d43d1167783c94131Winson Chung 1058e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected int getAssociatedLowerPageBound(int page) { 1059e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung return Math.max(0, page - 1); 1060e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 1061e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung protected int getAssociatedUpperPageBound(int page) { 1062e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung final int count = getChildCount(); 1063e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung return Math.min(page + 1, count - 1); 1064e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung } 1065e3193b93ad7bf33e2e45319084a99b9fc986622bWinson Chung 10665f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected void startChoiceMode(int mode, ActionMode.Callback callback) { 1067430c53bc80be01996b45e55687885d6c05314645Patrick Dubroy if (isChoiceMode(CHOICE_MODE_NONE)) { 1068430c53bc80be01996b45e55687885d6c05314645Patrick Dubroy mChoiceMode = mode; 1069430c53bc80be01996b45e55687885d6c05314645Patrick Dubroy mActionMode = startActionMode(callback); 1070430c53bc80be01996b45e55687885d6c05314645Patrick Dubroy } 10715f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10725f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 10732b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy public void endChoiceMode() { 10745f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung if (!isChoiceMode(CHOICE_MODE_NONE)) { 10755f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung mChoiceMode = CHOICE_MODE_NONE; 10765f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung resetCheckedGrandchildren(); 10779f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy mActionMode.finish(); 10789f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy mActionMode = null; 10795f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10805f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10815f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 10825f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected boolean isChoiceMode(int mode) { 10835f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung return mChoiceMode == mode; 10845f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10855f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 10865f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected ArrayList<Checkable> getCheckedGrandchildren() { 10875f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung ArrayList<Checkable> checked = new ArrayList<Checkable>(); 10885f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final int childCount = getChildCount(); 10895f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung for (int i = 0; i < childCount; ++i) { 10905f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i); 10915f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final int grandChildCount = layout.getChildCount(); 10925f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung for (int j = 0; j < grandChildCount; ++j) { 10935f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final View v = layout.getChildAt(j); 10949f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy if (v instanceof Checkable && ((Checkable) v).isChecked()) { 10955f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung checked.add((Checkable) v); 10965f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10975f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10985f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 10995f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung return checked; 11005f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11015f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 11029f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy /** 11039f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy * If in CHOICE_MODE_SINGLE and an item is checked, returns that item. 11049f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy * Otherwise, returns null. 11059f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy */ 11069f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy protected Checkable getSingleCheckedGrandchild() { 11079f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy if (mChoiceMode == CHOICE_MODE_SINGLE) { 11089f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy final int childCount = getChildCount(); 11099f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy for (int i = 0; i < childCount; ++i) { 11109f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i); 11119f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy final int grandChildCount = layout.getChildCount(); 11129f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy for (int j = 0; j < grandChildCount; ++j) { 11139f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy final View v = layout.getChildAt(j); 11149f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy if (v instanceof Checkable && ((Checkable) v).isChecked()) { 11159f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy return (Checkable) v; 11169f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11179f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11189f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11199f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11209f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy return null; 11219f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy } 11229f7aec8d4317d0407a41e12f236c962b225cb4c3Patrick Dubroy 11232b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy public Object getChosenItem() { 11242b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy View checkedView = (View) getSingleCheckedGrandchild(); 11252b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy if (checkedView != null) { 11262b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy return checkedView.getTag(); 11272b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy } 11282b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy return null; 11292b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy } 11302b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy 11315f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung protected void resetCheckedGrandchildren() { 11325f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung // loop through children, and set all of their children to _not_ be checked 11335f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final ArrayList<Checkable> checked = getCheckedGrandchildren(); 11345f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung for (int i = 0; i < checked.size(); ++i) { 11355f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung final Checkable c = checked.get(i); 11365f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung c.setChecked(false); 11375f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11385f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung } 11395f2aa4efeeb8b0133d891715d71553138d9f9ca7Winson Chung 114086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung /** 114186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * This method is called ONLY to synchronize the number of pages that the paged view has. 114286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * To actually fill the pages with information, implement syncPageItems() below. It is 114386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * guaranteed that syncPageItems() will be called for a particular page before it is shown, 114486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * and therefore, individual page items do not need to be updated in this method. 114586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung */ 1146321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public abstract void syncPages(); 114786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 114886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung /** 114986f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * This method is called to synchronize the items that are on a particular page. If views on 115086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung * the page can be reused, then they should be updated within this method. 115186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung */ 1152321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public abstract void syncPageItems(int page); 115386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 1154321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung public void invalidatePageData() { 11550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (mContentIsRefreshable) { 11560142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // Update all the pages 11570142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka syncPages(); 115886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 11590142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // Mark each of the pages as dirty 11600142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int count = getChildCount(); 11610142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageContent.clear(); 11620142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < count; ++i) { 11630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageContent.add(true); 11640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 116586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 11660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // Load any pages that are necessary for the current window of views 11670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka loadAssociatedPages(mCurrentPage); 11680142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mDirtyPageAlpha = true; 11690142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka requestLayout(); 11700142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1171321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung } 1172321e9ee68848d9e782fd557f69cc070308ffbc9cWinson Chung} 1173