ViewPager.java revision d84ef6c972b75c0ddeee88db2d66d40fff7519a8
1d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/*
2d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project
3d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn *
4d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * you may not use this file except in compliance with the License.
6d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * You may obtain a copy of the License at
7d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn *
8d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn *
10d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * See the License for the specific language governing permissions and
14d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * limitations under the License.
15d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */
16d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
175c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornpackage android.support.v4.view;
18d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
19481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.content.Context;
208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.content.res.TypedArray;
218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.database.DataSetObserver;
22560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.graphics.Canvas;
23481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.graphics.Rect;
24329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powellimport android.graphics.drawable.Drawable;
255de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powellimport android.os.Build;
26d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcel;
27d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcelable;
2869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powellimport android.os.SystemClock;
295c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompat;
305c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompatCreatorCallbacks;
31560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.support.v4.widget.EdgeEffectCompat;
32d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.AttributeSet;
33d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.Log;
342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.FocusFinder;
358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.Gravity;
362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent;
37d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.MotionEvent;
382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.SoundEffectConstants;
39d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.VelocityTracker;
40d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.View;
41d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewConfiguration;
42d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewGroup;
43218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackbornimport android.view.ViewParent;
44481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.view.accessibility.AccessibilityEvent;
451cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powellimport android.view.animation.Interpolator;
46d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.widget.Scroller;
47d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
48d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport java.util.ArrayList;
4966c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Collections;
5066c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Comparator;
51d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
52d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/**
53d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Layout manager that allows the user to flip left and right
545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * through pages of data.  You supply an implementation of a
555c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * {@link PagerAdapter} to generate the pages that the view shows.
565c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn *
575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * <p>Note this class is currently under early design and
585c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * development.  The API will likely change in later updates of
595c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * the compatibility library, requiring changes to the source code
605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * of apps when they are compiled against the newer version.</p>
617dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
627dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment},
637dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which is a convenient way to supply and manage the lifecycle of each page.
647dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * There are standard adapters implemented for using fragments with the ViewPager,
657dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which cover the most common use cases.  These are
667dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentPagerAdapter},
677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentStatePagerAdapter},
687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentPagerAdapter}, and
697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentStatePagerAdapter}; each of these
707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * classes have simple code showing how to build a full user interface
717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with them.
727dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
737dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is a more complicated example of ViewPager, using it in conjuction
747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with {@link android.app.ActionBar} tabs.  You can find other examples of using
757dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code.
767dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
777dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
787dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *      complete}
79d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */
80ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackbornpublic class ViewPager extends ViewGroup {
813661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private static final String TAG = "ViewPager";
82d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final boolean DEBUG = false;
83d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
84d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final boolean USE_CACHE = false;
85d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
8629a6184d74279156a9297dc67398712fb047fdc0Adam Powell    private static final int DEFAULT_OFFSCREEN_PAGES = 1;
871cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    private static final int MAX_SETTLE_DURATION = 600; // ms
88035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
8929a6184d74279156a9297dc67398712fb047fdc0Adam Powell
908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private static final int[] LAYOUT_ATTRS = new int[] {
918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        android.R.attr.layout_gravity
928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    };
938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
94d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    static class ItemInfo {
95ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        Object object;
96d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int position;
974c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        boolean scrolling;
98a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float widthFactor;
99a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float offset;
100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
101d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
10266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham    private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){
10366c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        @Override
10466c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        public int compare(ItemInfo lhs, ItemInfo rhs) {
10566c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham            return lhs.position - rhs.position;
106a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
107a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    };
10866c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham
1091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    private static final Interpolator sInterpolator = new Interpolator() {
1101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        public float getInterpolation(float t) {
1111cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell            t -= 1.0f;
112035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            return t * t * t * t * t + 1.0f;
1131cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        }
1141cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    };
1151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
116d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
117a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private final ItemInfo mTempItem = new ItemInfo();
118d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
119ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    private PagerAdapter mAdapter;
1203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private int mCurItem;   // Index of currently displayed page.
121d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mRestoredCurItem = -1;
122ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    private Parcelable mRestoredAdapterState = null;
1235c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private ClassLoader mRestoredClassLoader = null;
124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private Scroller mScroller;
1258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private PagerObserver mObserver;
126d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
127329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private int mPageMargin;
128329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private Drawable mMarginDrawable;
1298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mTopPageBounds;
1308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mBottomPageBounds;
131329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
132a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // Offsets of the first and last items, if known.
133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // Set during population, used to determine if we are at the beginning
134a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // or end of the pager data set during touch scrolling.
135a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private float mFirstOffset = -Float.MAX_VALUE;
136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private float mLastOffset = Float.MAX_VALUE;
137a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
138d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mChildWidthMeasureSpec;
139d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mChildHeightMeasureSpec;
140d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mInLayout;
141d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
142d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mScrollingCacheEnabled;
143d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mPopulatePending;
1454c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn    private boolean mScrolling;
14629a6184d74279156a9297dc67398712fb047fdc0Adam Powell    private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;
147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mIsBeingDragged;
149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mIsUnableToDrag;
150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mTouchSlop;
151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private float mInitialMotionX;
152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Position of the last motion event.
154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
155d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private float mLastMotionX;
156d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private float mLastMotionY;
157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * ID of the active pointer. This is used to retain consistency during
159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * drags/flings if multiple pointers are used.
160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mActivePointerId = INVALID_POINTER;
162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Sentinel value for no current active pointer.
164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Used by {@link #mActivePointerId}.
165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final int INVALID_POINTER = -1;
167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Determines speed during touch scrolling
170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private VelocityTracker mVelocityTracker;
172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mMinimumVelocity;
173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mMaximumVelocity;
174035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private int mFlingDistance;
175b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    private int mCloseEnough;
176b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell
177b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // If the pager is at least this close to its final position, complete the scroll
178b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // on touch down and let the user interact with the content inside instead of
179b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // "catching" the flinging pager.
180b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    private static final int CLOSE_ENOUGH = 2; // dp
181d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
18269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    private boolean mFakeDragging;
18369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    private long mFakeDragBeginTime;
18469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
185560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    private EdgeEffectCompat mLeftEdge;
186560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    private EdgeEffectCompat mRightEdge;
187560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
18897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    private boolean mFirstLayout = true;
189a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private boolean mNeedCalculatePageOffsets = false;
1908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private boolean mCalledSuper;
1918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mDecorChildCount;
19297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell
1933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private OnPageChangeListener mOnPageChangeListener;
1948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private OnPageChangeListener mInternalPageChangeListener;
1958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private OnAdapterChangeListener mAdapterChangeListener;
1963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
1973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    /**
19847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is in an idle, settled state. The current page
19947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * is fully in view and no animation is in progress.
20047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
20147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_IDLE = 0;
20247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
20347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
20447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is currently being dragged by the user.
20547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
20647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_DRAGGING = 1;
20747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
20847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
20947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is in the process of settling to a final position.
21047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
21147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_SETTLING = 2;
21247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
21347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    private int mScrollState = SCROLL_STATE_IDLE;
21447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
21547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
2163661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * Callback interface for responding to changing state of the selected page.
2173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     */
2183661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public interface OnPageChangeListener {
21947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
2203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        /**
2213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * This method will be invoked when the current page is scrolled, either as part
2223661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
2233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *
2243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param position Position index of the first page currently being displayed.
2253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *                 Page position+1 will be visible if positionOffset is nonzero.
2263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
2273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param positionOffsetPixels Value in pixels indicating the offset from position.
2283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         */
2293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
2303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        /**
23247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * This method will be invoked when a new page becomes selected. Animation is not
23347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * necessarily complete.
2343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *
2353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param position Position index of the new selected page.
2363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         */
2373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageSelected(int position);
23847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
23947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        /**
24047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * Called when the scroll state changes. Useful for discovering when the user
24147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * begins dragging, when the pager is automatically settling to the current page,
24247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * or when it is fully stopped/idle.
24347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         *
24447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @param state The new scroll state.
24547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_IDLE
24647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_DRAGGING
24747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_SETTLING
24847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         */
24947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        public void onPageScrollStateChanged(int state);
2503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
2513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    /**
2533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * Simple implementation of the {@link OnPageChangeListener} interface with stub
2543661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * implementations of each method. Extend this if you do not intend to override
2553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * every method of {@link OnPageChangeListener}.
2563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     */
2573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public static class SimpleOnPageChangeListener implements OnPageChangeListener {
2583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
2593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
2603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // This space for rent
2613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
2623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
2643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageSelected(int position) {
2653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // This space for rent
2663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
26747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
26847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        @Override
26947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        public void onPageScrollStateChanged(int state) {
27047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            // This space for rent
27147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
2723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
2733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
2758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Used internally to monitor when adapters are switched.
2768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
2778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    interface OnAdapterChangeListener {
2788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter);
2798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
2808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2811ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell    /**
2821ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     * Used internally to tag special types of child views that should be added as
2831ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     * pager decorations by default.
2841ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     */
2851ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell    interface Decor {}
2861ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell
287ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public ViewPager(Context context) {
288d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super(context);
28947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        initViewPager();
290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
291d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
292ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public ViewPager(Context context, AttributeSet attrs) {
293d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super(context, attrs);
29447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        initViewPager();
295d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
296d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
29747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    void initViewPager() {
298d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        setWillNotDraw(false);
2992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
3002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        setFocusable(true);
301560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        final Context context = getContext();
3021cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        mScroller = new Scroller(context, sInterpolator);
3031cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        final ViewConfiguration configuration = ViewConfiguration.get(context);
304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
305d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
307560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        mLeftEdge = new EdgeEffectCompat(context);
308560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        mRightEdge = new EdgeEffectCompat(context);
3091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
310035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final float density = context.getResources().getDisplayMetrics().density;
311035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
312b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell        mCloseEnough = (int) (CLOSE_ENOUGH * density);
313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
31547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    private void setScrollState(int newState) {
31647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        if (mScrollState == newState) {
31747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            return;
31847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
31947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
32047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        mScrollState = newState;
32147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        if (mOnPageChangeListener != null) {
32247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            mOnPageChangeListener.onPageScrollStateChanged(newState);
32347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
32447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    }
32547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
3268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
3278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a PagerAdapter that will supply views for this pager as needed.
3288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
3298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param adapter Adapter to use
3308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
331ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public void setAdapter(PagerAdapter adapter) {
3323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (mAdapter != null) {
3338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapter.unregisterDataSetObserver(mObserver);
3340d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mAdapter.startUpdate(this);
3350d6d2990ddacd3f419879149137f09a30c061436Minh Pham            for (int i = 0; i < mItems.size(); i++) {
3360d6d2990ddacd3f419879149137f09a30c061436Minh Pham                final ItemInfo ii = mItems.get(i);
3370d6d2990ddacd3f419879149137f09a30c061436Minh Pham                mAdapter.destroyItem(this, ii.position, ii.object);
3380d6d2990ddacd3f419879149137f09a30c061436Minh Pham            }
3390d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mAdapter.finishUpdate(this);
3400d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mItems.clear();
341a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            removeNonDecorViews();
3420d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mCurItem = 0;
343871a68b5daafd810623d680207652f87eb2d11ccMinh Pham            scrollTo(0, 0);
3443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
3453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
3468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final PagerAdapter oldAdapter = mAdapter;
347d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mAdapter = adapter;
348d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
349d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter != null) {
3503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (mObserver == null) {
3518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mObserver = new PagerObserver();
3523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
3538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapter.registerDataSetObserver(mObserver);
354d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mPopulatePending = false;
35591eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell            mFirstLayout = true;
356d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mRestoredCurItem >= 0) {
3575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
358d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                setCurrentItemInternal(mRestoredCurItem, false, true);
359d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mRestoredCurItem = -1;
360ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn                mRestoredAdapterState = null;
3615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                mRestoredClassLoader = null;
362d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            } else {
363d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                populate();
364d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
365d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
3668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mAdapterChangeListener != null && oldAdapter != adapter) {
3688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
3698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
370d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
372a7aea206661d601755bfac4165092d9130cba2bcAdam Powell    private void removeNonDecorViews() {
373a7aea206661d601755bfac4165092d9130cba2bcAdam Powell        for (int i = 0; i < getChildCount(); i++) {
374a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            final View child = getChildAt(i);
375a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
376a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            if (!lp.isDecor) {
377a7aea206661d601755bfac4165092d9130cba2bcAdam Powell                removeViewAt(i);
378a7aea206661d601755bfac4165092d9130cba2bcAdam Powell                i--;
379a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            }
380a7aea206661d601755bfac4165092d9130cba2bcAdam Powell        }
381a7aea206661d601755bfac4165092d9130cba2bcAdam Powell    }
382a7aea206661d601755bfac4165092d9130cba2bcAdam Powell
3838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
3848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Retrieve the current adapter supplying pages.
3858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
3868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @return The currently registered PagerAdapter
3878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
388ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public PagerAdapter getAdapter() {
389d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return mAdapter;
390d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
391d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
3928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    void setOnAdapterChangeListener(OnAdapterChangeListener listener) {
3938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mAdapterChangeListener = listener;
3948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
3958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
39697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    /**
39797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * Set the currently selected page. If the ViewPager has already been through its first
39891eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell     * layout with its current adapter there will be a smooth animated transition between
39991eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell     * the current item and the specified item.
40097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     *
40197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param item Item index to select
40297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     */
403d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void setCurrentItem(int item) {
404d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mPopulatePending = false;
40597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        setCurrentItemInternal(item, !mFirstLayout, false);
40697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    }
40797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell
40897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    /**
40997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * Set the currently selected page.
41097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     *
41197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param item Item index to select
41297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
41397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     */
41497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    public void setCurrentItem(int item, boolean smoothScroll) {
41597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mPopulatePending = false;
41697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        setCurrentItemInternal(item, smoothScroll, false);
417d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
418d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
419bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki    public int getCurrentItem() {
420bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki        return mCurItem;
421bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki    }
422bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki
423d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
4241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        setCurrentItemInternal(item, smoothScroll, always, 0);
4251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
4261cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
4271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
428d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter == null || mAdapter.getCount() <= 0) {
429d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
430d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
431d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
432d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (!always && mCurItem == item && mItems.size() != 0) {
433d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
436d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (item < 0) {
437d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            item = 0;
438d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else if (item >= mAdapter.getCount()) {
439d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            item = mAdapter.getCount() - 1;
440d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
44129a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int pageLimit = mOffscreenPageLimit;
44229a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
4434c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // We are doing a jump by more than one page.  To avoid
4444c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // glitches, we want to keep all current pages in the view
4454c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // until the scroll ends.
4464c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            for (int i=0; i<mItems.size(); i++) {
4474c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                mItems.get(i).scrolling = true;
4484c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            }
4494c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
45047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        final boolean dispatchSelected = mCurItem != item;
451a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        populate(item);
452a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo curInfo = infoForPosition(item);
45331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        int destX = 0;
45431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        if (curInfo != null) {
45531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            final int width = getWidth();
45631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            destX = (int) (width * Math.max(mFirstOffset,
45731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                    Math.min(curInfo.offset, mLastOffset)));
45831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        }
459d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (smoothScroll) {
4601cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell            smoothScrollTo(destX, 0, velocity);
46147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            if (dispatchSelected && mOnPageChangeListener != null) {
46247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                mOnPageChangeListener.onPageSelected(item);
46347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            }
4648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (dispatchSelected && mInternalPageChangeListener != null) {
4658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mInternalPageChangeListener.onPageSelected(item);
4668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
467d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
46847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            if (dispatchSelected && mOnPageChangeListener != null) {
4693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mOnPageChangeListener.onPageSelected(item);
4703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
4718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (dispatchSelected && mInternalPageChangeListener != null) {
4728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mInternalPageChangeListener.onPageSelected(item);
4738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
47447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            completeScroll();
475329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            scrollTo(destX, 0);
476d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
477d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
478d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
4798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
4808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a listener that will be invoked whenever the page changes or is incrementally
4818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * scrolled. See {@link OnPageChangeListener}.
4828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
4838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param listener Listener to set
4848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
4853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public void setOnPageChangeListener(OnPageChangeListener listener) {
4863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        mOnPageChangeListener = listener;
4873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
4883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
489d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
4908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a separate OnPageChangeListener for internal use by the support library.
4918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
4928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param listener Listener to set
4938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @return The old listener that was set, if any.
4948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
4958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {
4968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        OnPageChangeListener oldListener = mInternalPageChangeListener;
4978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mInternalPageChangeListener = listener;
4988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return oldListener;
4998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
5008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
5018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
50229a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * Returns the number of pages that will be retained to either side of the
50329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * current page in the view hierarchy in an idle state. Defaults to 1.
50429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
50529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @return How many pages will be kept offscreen on either side
50629a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @see #setOffscreenPageLimit(int)
50729a6184d74279156a9297dc67398712fb047fdc0Adam Powell     */
50829a6184d74279156a9297dc67398712fb047fdc0Adam Powell    public int getOffscreenPageLimit() {
50929a6184d74279156a9297dc67398712fb047fdc0Adam Powell        return mOffscreenPageLimit;
51029a6184d74279156a9297dc67398712fb047fdc0Adam Powell    }
51129a6184d74279156a9297dc67398712fb047fdc0Adam Powell
51229a6184d74279156a9297dc67398712fb047fdc0Adam Powell    /**
51329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * Set the number of pages that should be retained to either side of the
51429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * current page in the view hierarchy in an idle state. Pages beyond this
51529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * limit will be recreated from the adapter when needed.
51629a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
51729a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * <p>This is offered as an optimization. If you know in advance the number
51829a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * of pages you will need to support or have lazy-loading mechanisms in place
51929a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * on your pages, tweaking this setting can have benefits in perceived smoothness
52029a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * of paging animations and interaction. If you have a small number of pages (3-4)
52129a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * that you can keep active all at once, less time will be spent in layout for
52229a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * newly created view subtrees as the user pages back and forth.</p>
52329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
52429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * <p>You should keep this limit low, especially if your pages have complex layouts.
52529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * This setting defaults to 1.</p>
52629a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
52729a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @param limit How many pages will be kept offscreen in an idle state.
52829a6184d74279156a9297dc67398712fb047fdc0Adam Powell     */
52929a6184d74279156a9297dc67398712fb047fdc0Adam Powell    public void setOffscreenPageLimit(int limit) {
53029a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (limit < DEFAULT_OFFSCREEN_PAGES) {
53129a6184d74279156a9297dc67398712fb047fdc0Adam Powell            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
53229a6184d74279156a9297dc67398712fb047fdc0Adam Powell                    DEFAULT_OFFSCREEN_PAGES);
53329a6184d74279156a9297dc67398712fb047fdc0Adam Powell            limit = DEFAULT_OFFSCREEN_PAGES;
53429a6184d74279156a9297dc67398712fb047fdc0Adam Powell        }
53529a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (limit != mOffscreenPageLimit) {
53629a6184d74279156a9297dc67398712fb047fdc0Adam Powell            mOffscreenPageLimit = limit;
53729a6184d74279156a9297dc67398712fb047fdc0Adam Powell            populate();
53829a6184d74279156a9297dc67398712fb047fdc0Adam Powell        }
53929a6184d74279156a9297dc67398712fb047fdc0Adam Powell    }
54029a6184d74279156a9297dc67398712fb047fdc0Adam Powell
54129a6184d74279156a9297dc67398712fb047fdc0Adam Powell    /**
542329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set the margin between pages.
543329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
544329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param marginPixels Distance between adjacent pages in pixels
545329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #getPageMargin()
546329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #setPageMarginDrawable(Drawable)
547329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #setPageMarginDrawable(int)
548329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
549329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMargin(int marginPixels) {
550329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final int oldMargin = mPageMargin;
551329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        mPageMargin = marginPixels;
552329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
553329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final int width = getWidth();
554329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        recomputeScrollPosition(width, width, marginPixels, oldMargin);
555329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
556329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        requestLayout();
557329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
558329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
559329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
560329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Return the margin between pages.
561329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
562329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @return The size of the margin in pixels
563329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
564329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public int getPageMargin() {
565329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        return mPageMargin;
566329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
567329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
568329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
569329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set a drawable that will be used to fill the margin between pages.
570329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
571329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param d Drawable to display between pages
572329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
573329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMarginDrawable(Drawable d) {
574329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        mMarginDrawable = d;
575329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        if (d != null) refreshDrawableState();
576329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        setWillNotDraw(d == null);
577329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        invalidate();
578329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
579329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
580329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
581329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set a drawable that will be used to fill the margin between pages.
582329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
583329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param resId Resource ID of a drawable to display between pages
584329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
585329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMarginDrawable(int resId) {
586329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        setPageMarginDrawable(getContext().getResources().getDrawable(resId));
587329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
588329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
589329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
590329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected boolean verifyDrawable(Drawable who) {
591329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        return super.verifyDrawable(who) || who == mMarginDrawable;
592329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
593329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
594329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
595329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected void drawableStateChanged() {
596329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        super.drawableStateChanged();
597329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final Drawable d = mMarginDrawable;
598329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        if (d != null && d.isStateful()) {
599329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            d.setState(getDrawableState());
600329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
601329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
602329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
6031cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // We want the duration of the page snap animation to be influenced by the distance that
6041cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // the screen has to travel, however, we don't want this duration to be effected in a
6051cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
6061cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // of travel has on the overall snap duration.
6071cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    float distanceInfluenceForSnapDuration(float f) {
6081cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        f -= 0.5f; // center the values about 0.
6091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        f *= 0.3f * Math.PI / 2.0f;
6101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        return (float) Math.sin(f);
6111cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
6121cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
613329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
614d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
615d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     *
616cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param x the number of pixels to scroll by on the X axis
617cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param y the number of pixels to scroll by on the Y axis
618d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
619d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void smoothScrollTo(int x, int y) {
6201cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        smoothScrollTo(x, y, 0);
6211cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
6221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
6231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    /**
6241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
6251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     *
6261cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param x the number of pixels to scroll by on the X axis
6271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param y the number of pixels to scroll by on the Y axis
6281cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)
6291cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     */
6301cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    void smoothScrollTo(int x, int y, int velocity) {
631d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (getChildCount() == 0) {
632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Nothing to do.
633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
634d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
635d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
636d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int sx = getScrollX();
637d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int sy = getScrollY();
6383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        int dx = x - sx;
6393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        int dy = y - sy;
6403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (dx == 0 && dy == 0) {
64147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            completeScroll();
64231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            populate();
6433040c142491acd4a09e7d0add073be0067aec2d5Adam Powell            setScrollState(SCROLL_STATE_IDLE);
6443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            return;
6453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
6463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
6473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        setScrollingCacheEnabled(true);
6484c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        mScrolling = true;
64947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        setScrollState(SCROLL_STATE_SETTLING);
6501cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
651035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final int width = getWidth();
652035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final int halfWidth = width / 2;
653035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
654035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final float distance = halfWidth + halfWidth *
655035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                distanceInfluenceForSnapDuration(distanceRatio);
6561cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
657035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        int duration = 0;
6581cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        velocity = Math.abs(velocity);
6591cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        if (velocity > 0) {
660035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
6611cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        } else {
662a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
663a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
664035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            duration = (int) ((pageDelta + 1) * 100);
6651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        }
6661cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        duration = Math.min(duration, MAX_SETTLE_DURATION);
6671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
6681cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        mScroller.startScroll(sx, sy, dx, dy, duration);
669b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell        ViewCompat.postInvalidateOnAnimation(this);
670d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
671d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
672a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    ItemInfo addNewItem(int position, int index) {
673d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ItemInfo ii = new ItemInfo();
674d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ii.position = position;
6755c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        ii.object = mAdapter.instantiateItem(this, position);
676a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ii.widthFactor = mAdapter.getPageWidth(position);
677a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (index < 0 || index >= mItems.size()) {
678d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mItems.add(ii);
679d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
680d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mItems.add(index, ii);
681d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
682a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        return ii;
683d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
684d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
6853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    void dataSetChanged() {
6863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        // This method only gets called if our observer is attached, so mAdapter is non-null.
6873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
6881a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell        boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 &&
6891a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell                mItems.size() < mAdapter.getCount();
6901e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell        int newCurrItem = mCurItem;
6913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
6929508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        boolean isUpdating = false;
6933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        for (int i = 0; i < mItems.size(); i++) {
6943661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            final ItemInfo ii = mItems.get(i);
6953661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            final int newPos = mAdapter.getItemPosition(ii.object);
6963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
6973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
6983661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                continue;
6993661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
7003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (newPos == PagerAdapter.POSITION_NONE) {
7023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mItems.remove(i);
7033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                i--;
7049508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
7059508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                if (!isUpdating) {
7069508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                    mAdapter.startUpdate(this);
7079508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                    isUpdating = true;
7089508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                }
7099508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
7103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mAdapter.destroyItem(this, ii.position, ii.object);
7113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                needPopulate = true;
7123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7133661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (mCurItem == ii.position) {
7143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    // Keep the current item in the valid range
7153661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1));
7161a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell                    needPopulate = true;
7173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
7183661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                continue;
7193661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
7203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (ii.position != newPos) {
7223661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (ii.position == mCurItem) {
7233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    // Our current item changed position. Follow it.
7243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    newCurrItem = newPos;
7253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
7263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                ii.position = newPos;
7283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                needPopulate = true;
7293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
7303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
7313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7329508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        if (isUpdating) {
7339508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell            mAdapter.finishUpdate(this);
7349508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        }
7359508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
73666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        Collections.sort(mItems, COMPARATOR);
73766c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham
738a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (needPopulate) {
739a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Reset our known page widths; populate will recompute them.
740a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int childCount = getChildCount();
741a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int i = 0; i < childCount; i++) {
742a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final View child = getChildAt(i);
743a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
744a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (!lp.isDecor) {
745a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    lp.widthFactor = 0.f;
746a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
747a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
748a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
749d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell            setCurrentItemInternal(newCurrItem, false, true);
7503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            requestLayout();
7513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
7523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
7533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
754d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void populate() {
755a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        populate(mCurItem);
756a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
757a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
758a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    void populate(int newCurrentItem) {
759a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ItemInfo oldCurInfo = null;
760a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mCurItem != newCurrentItem) {
761a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            oldCurInfo = infoForPosition(mCurItem);
762a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            mCurItem = newCurrentItem;
763a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
764a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
765d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter == null) {
766d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
767d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
768d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
769d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Bail now if we are waiting to populate.  This is to hold off
770d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // on creating views from the time the user releases their finger to
771d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // fling to a new position until we have finished the scroll to
772d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // that position, avoiding glitches from happening at that point.
773d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mPopulatePending) {
7743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
775d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
776d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
777d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
778ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // Also, don't populate until we are attached to a window.  This is to
779ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // avoid trying to populate before we have restored our view hierarchy
780ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // state and conflicting with what is restored.
781ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        if (getWindowToken() == null) {
782ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            return;
783ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        }
784ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn
7855c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mAdapter.startUpdate(this);
786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
78729a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int pageLimit = mOffscreenPageLimit;
78829a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int startPos = Math.max(0, mCurItem - pageLimit);
7894c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        final int N = mAdapter.getCount();
79029a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int endPos = Math.min(N-1, mCurItem + pageLimit);
791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
792a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Locate the currently focused item or add it if needed.
793a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int curIndex = -1;
794a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ItemInfo curItem = null;
795a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
796a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(curIndex);
797a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position >= mCurItem) {
798a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (ii.position == mCurItem) curItem = ii;
799a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                break;
800a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
801a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
803a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (curItem == null && N > 0) {
804a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            curItem = addNewItem(mCurItem, curIndex);
805a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
806a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
807a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Fill 3x the available width or up to the number of offscreen
808a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // pages requested to either side, whichever is larger.
809a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // If we have no current item we have no work to do.
810a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (curItem != null) {
811a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float extraWidthLeft = 0.f;
812a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int itemIndex = curIndex - 1;
813a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
81431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            final float leftWidthNeeded = 2.f - curItem.widthFactor;
815a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int pos = mCurItem - 1; pos >= 0; pos--) {
81631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
817a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (ii == null) {
818a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        break;
819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (pos == ii.position && !ii.scrolling) {
821a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        mItems.remove(itemIndex);
822a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        mAdapter.destroyItem(this, pos, ii.object);
823a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex--;
824a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        curIndex--;
825a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
826a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
827a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else if (ii != null && pos == ii.position) {
828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    extraWidthLeft += ii.widthFactor;
829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    itemIndex--;
830a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
831a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else {
832a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = addNewItem(pos, itemIndex + 1);
833a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    extraWidthLeft += ii.widthFactor;
834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    curIndex++;
835a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
8364c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                }
837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
838d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float extraWidthRight = curItem.widthFactor;
840a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            itemIndex = curIndex + 1;
841a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (extraWidthRight < 2.f) {
842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
843a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = mCurItem + 1; pos < N; pos++) {
844a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (extraWidthRight >= 2.f && pos > endPos) {
845a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (ii == null) {
846a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            break;
847a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
848a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (pos == ii.position && !ii.scrolling) {
849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            mItems.remove(itemIndex);
850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            mAdapter.destroyItem(this, pos, ii.object);
851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
852a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
853a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    } else if (ii != null && pos == ii.position) {
854a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        extraWidthRight += ii.widthFactor;
855a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
857a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    } else {
858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = addNewItem(pos, itemIndex);
859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
860a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        extraWidthRight += ii.widthFactor;
861a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
862a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
864d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            calculatePageOffsets(curItem, curIndex, oldCurInfo);
867d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
868d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
8694c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        if (DEBUG) {
8704c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            Log.i(TAG, "Current page list:");
8714c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            for (int i=0; i<mItems.size(); i++) {
8724c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);
873d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
874d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
875d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
8762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
8772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
8785c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mAdapter.finishUpdate(this);
8792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
880a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Check width measurement of current pages. Update LayoutParams as needed.
881a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int childCount = getChildCount();
882a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < childCount; i++) {
883a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final View child = getChildAt(i);
884a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
885a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (!lp.isDecor && lp.widthFactor == 0.f) {
886a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                // 0 means requery the adapter for this, it doesn't have a valid width.
887a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final ItemInfo ii = infoForChild(child);
888a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (ii != null) {
889a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    lp.widthFactor = ii.widthFactor;
890a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
891a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
892a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
893a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
8942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (hasFocus()) {
8952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            View currentFocused = findFocus();
896218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
8972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (ii == null || ii.position != mCurItem) {
8982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                for (int i=0; i<getChildCount(); i++) {
8992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    View child = getChildAt(i);
9002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    ii = infoForChild(child);
9012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (ii != null && ii.position == mCurItem) {
9022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        if (child.requestFocus(FOCUS_FORWARD)) {
9032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                            break;
9042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        }
9052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
9062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
9072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
9082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
909d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
910d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
911a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) {
912a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int N = mAdapter.getCount();
913a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int width = getWidth();
914a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
915a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Fix up offsets for later layout.
916a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (oldCurInfo != null) {
917a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int oldCurPosition = oldCurInfo.position;
918a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Base offsets off of oldCurInfo.
919a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (oldCurPosition < curItem.position) {
920a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                int itemIndex = 0;
921a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii = null;
9226bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell                float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset;
923a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = oldCurPosition + 1;
924a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos <= curItem.position && itemIndex < mItems.size(); pos++) {
925a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(itemIndex);
926a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos > ii.position && itemIndex < mItems.size() - 1) {
927a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
928a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = mItems.get(itemIndex);
929a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos < ii.position) {
931a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // We don't have an item populated for this,
932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // ask the adapter for an offset.
933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        offset += mAdapter.getPageWidth(pos) + marginOffset;
934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos++;
935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii.offset = offset;
937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset += ii.widthFactor + marginOffset;
938a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
939a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            } else if (oldCurPosition > curItem.position) {
940a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                int itemIndex = mItems.size() - 1;
941a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii = null;
942a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                float offset = oldCurInfo.offset;
943a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = oldCurPosition - 1;
944a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos >= curItem.position && itemIndex >= 0; pos--) {
945a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(itemIndex);
946a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos < ii.position && itemIndex > 0) {
947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex--;
948a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = mItems.get(itemIndex);
949a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
950a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos > ii.position) {
951a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // We don't have an item populated for this,
952a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // ask the adapter for an offset.
953a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        offset -= mAdapter.getPageWidth(pos) + marginOffset;
954a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos--;
955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset -= ii.widthFactor + marginOffset;
957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii.offset = offset;
958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
961a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
962a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Base all offsets off of curItem.
963a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int itemCount = mItems.size();
964a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float offset = curItem.offset;
965a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int pos = curItem.position - 1;
966a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE;
96731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        mLastOffset = curItem.position == N - 1 ?
96831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE;
969a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Previous pages
970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = curIndex - 1; i >= 0; i--, pos--) {
971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(i);
972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            while (pos > ii.position) {
973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                offset -= mAdapter.getPageWidth(pos--) + marginOffset;
974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset -= ii.widthFactor + marginOffset;
976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ii.offset = offset;
977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position == 0) mFirstOffset = offset;
978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        offset = curItem.offset + curItem.widthFactor + marginOffset;
980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        pos = curItem.position + 1;
981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Next pages
982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = curIndex + 1; i < itemCount; i++, pos++) {
983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(i);
984a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            while (pos < ii.position) {
985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                offset += mAdapter.getPageWidth(pos++) + marginOffset;
986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
98731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            if (ii.position == N - 1) {
98831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                mLastOffset = offset + ii.widthFactor - 1;
98931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            }
990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ii.offset = offset;
991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset += ii.widthFactor + marginOffset;
992a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
993a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mNeedCalculatePageOffsets = false;
995a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
996a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
9977dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn    /**
9987dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * This is the persistent state that is saved by ViewPager.  Only needed
9997dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * if you are creating a sublass of ViewPager that must save its own
10007dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * state, in which case it should implement a subclass of this which
10017dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * contains that state.
10027dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     */
1003d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public static class SavedState extends BaseSavedState {
1004d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int position;
1005ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        Parcelable adapterState;
10065c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        ClassLoader loader;
1007d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
10085c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        public SavedState(Parcelable superState) {
1009d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super(superState);
1010d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1011d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1012d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        @Override
1013d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        public void writeToParcel(Parcel out, int flags) {
1014d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.writeToParcel(out, flags);
1015d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            out.writeInt(position);
10165c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            out.writeParcelable(adapterState, flags);
1017d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1018d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1019d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        @Override
1020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        public String toString() {
1021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return "FragmentPager.SavedState{"
1022d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    + Integer.toHexString(System.identityHashCode(this))
1023d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    + " position=" + position + "}";
1024d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1025d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
10265c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        public static final Parcelable.Creator<SavedState> CREATOR
10275c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
10285c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    @Override
10295c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
10305c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        return new SavedState(in, loader);
10315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    }
10325c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    @Override
10335c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    public SavedState[] newArray(int size) {
10345c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        return new SavedState[size];
10355c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    }
10365c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                });
10375c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
10385c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        SavedState(Parcel in, ClassLoader loader) {
1039d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super(in);
10405c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            if (loader == null) {
10415c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                loader = getClass().getClassLoader();
1042ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            }
10435c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            position = in.readInt();
10445c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            adapterState = in.readParcelable(loader);
10455c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            this.loader = loader;
1046d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1047d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1048d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1049d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1050d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public Parcelable onSaveInstanceState() {
1051d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        Parcelable superState = super.onSaveInstanceState();
1052d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        SavedState ss = new SavedState(superState);
1053d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ss.position = mCurItem;
1054677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki        if (mAdapter != null) {
1055677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki            ss.adapterState = mAdapter.saveState();
1056677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki        }
1057d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return ss;
1058d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1059d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1060d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1061d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void onRestoreInstanceState(Parcelable state) {
1062d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (!(state instanceof SavedState)) {
1063d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.onRestoreInstanceState(state);
1064d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
1065d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1066d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1067d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        SavedState ss = (SavedState)state;
1068d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super.onRestoreInstanceState(ss.getSuperState());
1069d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1070d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter != null) {
10715c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mAdapter.restoreState(ss.adapterState, ss.loader);
1072d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setCurrentItemInternal(ss.position, false, true);
1073d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
1074d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mRestoredCurItem = ss.position;
1075ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            mRestoredAdapterState = ss.adapterState;
10765c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mRestoredClassLoader = ss.loader;
1077d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1078d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1079d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1080d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
10818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public void addView(View child, int index, ViewGroup.LayoutParams params) {
10821ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        if (!checkLayoutParams(params)) {
10831ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell            params = generateLayoutParams(params);
10841ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        }
10851ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        final LayoutParams lp = (LayoutParams) params;
10861ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        lp.isDecor |= child instanceof Decor;
1087d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mInLayout) {
10888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (lp != null && lp.isDecor) {
10898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                throw new IllegalStateException("Cannot add pager decor view during layout");
10908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
1091a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lp.needsMeasure = true;
1092d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            addViewInLayout(child, index, params);
1093d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
1094d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.addView(child, index, params);
1095d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1096d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1097d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (USE_CACHE) {
1098d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (child.getVisibility() != GONE) {
1099d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                child.setDrawingCacheEnabled(mScrollingCacheEnabled);
1100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            } else {
1101d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                child.setDrawingCacheEnabled(false);
1102d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1103d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1105d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1106d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    ItemInfo infoForChild(View child) {
1107d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i=0; i<mItems.size(); i++) {
1108d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            ItemInfo ii = mItems.get(i);
1109ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            if (mAdapter.isViewFromObject(child, ii.object)) {
1110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return ii;
1111d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1112d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1113d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return null;
1114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1116218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn    ItemInfo infoForAnyChild(View child) {
1117218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        ViewParent parent;
1118218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        while ((parent=child.getParent()) != this) {
1119218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            if (parent == null || !(parent instanceof View)) {
1120218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn                return null;
1121218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            }
1122218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            child = (View)parent;
1123218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        }
1124218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        return infoForChild(child);
1125218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn    }
1126218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn
1127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    ItemInfo infoForPosition(int position) {
1128a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < mItems.size(); i++) {
1129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(i);
1130a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position == position) {
1131a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                return ii;
1132a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1134a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        return null;
1135a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
1136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1137d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1138ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    protected void onAttachedToWindow() {
1139ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        super.onAttachedToWindow();
114097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mFirstLayout = true;
1141ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    }
1142ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn
1143ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    @Override
1144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1145d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // For simple implementation, or internal size is always 0.
1146d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // We depend on the container to specify the layout size of
1147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // our view.  We can't really know what it is since we will be
1148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // adding and removing different arbitrary views and do not
1149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // want the layout to change as this happens.
1150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
1151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                getDefaultSize(0, heightMeasureSpec));
1152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Children are just made to fill our space.
11548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int childWidthSize = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
11558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
11568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
11578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        /*
11588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * Make sure all children have been properly measured. Decor views first.
11598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * Right now we cheat and make this less complicated by assuming decor
11608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * views won't intersect. We will pin to edges based on gravity.
11618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         */
1162862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell        int size = getChildCount();
11638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        for (int i = 0; i < size; ++i) {
11648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final View child = getChildAt(i);
11658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (child.getVisibility() != GONE) {
11668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
11678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp != null && lp.isDecor) {
11688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
11698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
11708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    int widthMode = MeasureSpec.AT_MOST;
11718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    int heightMode = MeasureSpec.AT_MOST;
11728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
11738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
11748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
11758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (consumeVertical) {
11768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        widthMode = MeasureSpec.EXACTLY;
11778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    } else if (consumeHorizontal) {
11788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        heightMode = MeasureSpec.EXACTLY;
11798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
11808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
1181a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int widthSize = childWidthSize;
1182a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int heightSize = childHeightSize;
1183a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.width != LayoutParams.WRAP_CONTENT) {
1184a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        widthMode = MeasureSpec.EXACTLY;
1185a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (lp.width != LayoutParams.FILL_PARENT) {
1186a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            widthSize = lp.width;
1187a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
1188a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1189a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.height != LayoutParams.WRAP_CONTENT) {
1190a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        heightMode = MeasureSpec.EXACTLY;
1191a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (lp.height != LayoutParams.FILL_PARENT) {
1192a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            heightSize = lp.height;
1193a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
1194a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1195a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
1196a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
11978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    child.measure(widthSpec, heightSpec);
11988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
11998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (consumeVertical) {
12008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childHeightSize -= child.getMeasuredHeight();
12018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    } else if (consumeHorizontal) {
12028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childWidthSize -= child.getMeasuredWidth();
12038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
12048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
12058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
12068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
12078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
12088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
12098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
1210d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1211d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Make sure we have created all fragments that we need to have shown.
1212d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = true;
1213d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        populate();
1214d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = false;
1215d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
12168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        // Page views next.
1217862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell        size = getChildCount();
1218d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i = 0; i < size; ++i) {
1219d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            final View child = getChildAt(i);
1220d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (child.getVisibility() != GONE) {
1221d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child
12228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        + ": " + mChildWidthMeasureSpec);
12238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
12248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
12258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp == null || !lp.isDecor) {
1226a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int widthSpec = MeasureSpec.makeMeasureSpec(
1227a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
1228a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    child.measure(widthSpec, mChildHeightMeasureSpec);
12298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
1230d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1231d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1232d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1233d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1234d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1235d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1236d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super.onSizeChanged(w, h, oldw, oldh);
1237d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1238d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Make sure scroll position is set correctly.
1239053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell        if (w != oldw) {
1240329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);
1241329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
1242329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
1243329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
1244329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) {
12455f6568e7e269783e2668527461878cadfbe65215Adam Powell        final int widthWithMargin = width + margin;
124691eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell        if (oldWidth > 0 && !mItems.isEmpty()) {
1247a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int xpos = getScrollX();
12485f6568e7e269783e2668527461878cadfbe65215Adam Powell            final int oldWidthWithMargin = oldWidth + oldMargin;
12495f6568e7e269783e2668527461878cadfbe65215Adam Powell            final float pageOffset = (float) xpos / oldWidthWithMargin;
12505f6568e7e269783e2668527461878cadfbe65215Adam Powell            final int newOffsetPixels = (int) (pageOffset * widthWithMargin);
1251a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
12525f6568e7e269783e2668527461878cadfbe65215Adam Powell            scrollTo(newOffsetPixels, getScrollY());
1253329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            if (!mScroller.isFinished()) {
1254329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell                // We now return to your regularly scheduled scroll, already in progress.
1255329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell                final int newDuration = mScroller.getDuration() - mScroller.timePassed();
1256a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo targetInfo = infoForPosition(mCurItem);
12575f6568e7e269783e2668527461878cadfbe65215Adam Powell                mScroller.startScroll(newOffsetPixels, 0,
12585f6568e7e269783e2668527461878cadfbe65215Adam Powell                        (int) (targetInfo.offset * widthWithMargin), 0, newDuration);
1259329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            }
1260329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        } else {
1261a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = infoForPosition(mCurItem);
126231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            final int scrollPos =
12635f6568e7e269783e2668527461878cadfbe65215Adam Powell                    (int) ((ii != null ? Math.min(ii.offset, mLastOffset) : 0) * widthWithMargin);
1264329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            if (scrollPos != getScrollX()) {
1265329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell                completeScroll();
1266053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell                scrollTo(scrollPos, getScrollY());
12679bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell            }
1268d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1269d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1270d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1271d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1272d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onLayout(boolean changed, int l, int t, int r, int b) {
1273d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = true;
1274d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        populate();
1275d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = false;
1276d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1277d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int count = getChildCount();
12788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int width = r - l;
12798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int height = b - t;
12808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingLeft = getPaddingLeft();
12818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingTop = getPaddingTop();
12828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingRight = getPaddingRight();
12838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingBottom = getPaddingBottom();
12848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int scrollX = getScrollX();
12858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
12868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int decorCount = 0;
1287d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1288a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // First pass - decor views. We need to do this in two passes so that
1289a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // we have the proper offsets for non-decor views later.
1290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i = 0; i < count; i++) {
12918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final View child = getChildAt(i);
12928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (child.getVisibility() != GONE) {
12938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
12948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childLeft = 0;
12958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childTop = 0;
12968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp.isDecor) {
12978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
12988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
12998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    switch (hgrav) {
13008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        default:
13018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = paddingLeft;
13028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.LEFT:
13048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = paddingLeft;
13058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingLeft += child.getMeasuredWidth();
13068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.CENTER_HORIZONTAL:
13088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
13098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                    paddingLeft);
13108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.RIGHT:
13128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = width - paddingRight - child.getMeasuredWidth();
13138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingRight += child.getMeasuredWidth();
13148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
13168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    switch (vgrav) {
13178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        default:
13188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = paddingTop;
13198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.TOP:
13218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = paddingTop;
13228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingTop += child.getMeasuredHeight();
13238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.CENTER_VERTICAL:
13258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = Math.max((height - child.getMeasuredHeight()) / 2,
13268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                    paddingTop);
13278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.BOTTOM:
13298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = height - paddingBottom - child.getMeasuredHeight();
13308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingBottom += child.getMeasuredHeight();
13318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
13338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    childLeft += scrollX;
1334abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                    child.layout(childLeft, childTop,
1335abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childLeft + child.getMeasuredWidth(),
1336abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childTop + child.getMeasuredHeight());
1337a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    decorCount++;
1338a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1339a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1340a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1341a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1342a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Page views. Do this once we have the right padding offsets from above.
1343a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < count; i++) {
1344a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final View child = getChildAt(i);
1345a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (child.getVisibility() != GONE) {
1346a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1347a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii;
1348a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (!lp.isDecor && (ii = infoForChild(child)) != null) {
1349a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int loff = (int) (width * ii.offset);
1350a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int childLeft = paddingLeft + loff;
1351a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int childTop = paddingTop;
1352a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.needsMeasure) {
1353a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // This was added during layout and needs measurement.
1354a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // Do it now that we know what we're working with.
1355a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        lp.needsMeasure = false;
1356a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        final int widthSpec = MeasureSpec.makeMeasureSpec(
1357a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                (int) ((width - paddingLeft - paddingRight) * lp.widthFactor),
1358a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                MeasureSpec.EXACTLY);
1359a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        final int heightSpec = MeasureSpec.makeMeasureSpec(
1360a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                (int) (height - paddingTop - paddingBottom),
1361a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                MeasureSpec.EXACTLY);
1362a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        child.measure(widthSpec, heightSpec);
1363a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
13648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object
13658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth()
13668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            + "x" + child.getMeasuredHeight());
1367abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                    child.layout(childLeft, childTop,
1368abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childLeft + child.getMeasuredWidth(),
1369abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childTop + child.getMeasuredHeight());
13708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
1371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1372d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
13738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mTopPageBounds = paddingTop;
13748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mBottomPageBounds = height - paddingBottom;
13758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mDecorChildCount = decorCount;
137697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mFirstLayout = false;
1377d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1378d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void computeScroll() {
1381a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
1382a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int oldX = getScrollX();
1383a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int oldY = getScrollY();
1384a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int x = mScroller.getCurrX();
1385a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int y = mScroller.getCurrY();
13863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
1387a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (oldX != x || oldY != y) {
1388a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                scrollTo(x, y);
13894783095cc69fa85e484132337526c94d42d41c43Adam Powell                if (!pageScrolled(x)) {
13904783095cc69fa85e484132337526c94d42d41c43Adam Powell                    mScroller.abortAnimation();
13914783095cc69fa85e484132337526c94d42d41c43Adam Powell                    scrollTo(0, y);
13924783095cc69fa85e484132337526c94d42d41c43Adam Powell                }
1393d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1394a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1395a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Keep on drawing until the animation has finished.
1396b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
1397a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            return;
1398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
13994c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn
14004c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        // Done with scroll, clean up state.
140147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        completeScroll();
1402d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1403d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
14044783095cc69fa85e484132337526c94d42d41c43Adam Powell    private boolean pageScrolled(int xpos) {
14054783095cc69fa85e484132337526c94d42d41c43Adam Powell        if (mItems.size() == 0) {
14064783095cc69fa85e484132337526c94d42d41c43Adam Powell            mCalledSuper = false;
14074783095cc69fa85e484132337526c94d42d41c43Adam Powell            onPageScrolled(0, 0, 0);
14084783095cc69fa85e484132337526c94d42d41c43Adam Powell            if (!mCalledSuper) {
14094783095cc69fa85e484132337526c94d42d41c43Adam Powell                throw new IllegalStateException(
14104783095cc69fa85e484132337526c94d42d41c43Adam Powell                        "onPageScrolled did not call superclass implementation");
14114783095cc69fa85e484132337526c94d42d41c43Adam Powell            }
14124783095cc69fa85e484132337526c94d42d41c43Adam Powell            return false;
14134783095cc69fa85e484132337526c94d42d41c43Adam Powell        }
1414a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo ii = infoForCurrentScrollPosition();
1415a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int width = getWidth();
1416a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int widthWithMargin = width + mPageMargin;
1417a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = (float) mPageMargin / width;
1418a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int currentPage = ii.position;
1419a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float pageOffset = (((float) xpos / width) - ii.offset) /
1420a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                (ii.widthFactor + marginOffset);
1421a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int offsetPixels = (int) (pageOffset * widthWithMargin);
14228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCalledSuper = false;
1424a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        onPageScrolled(currentPage, pageOffset, offsetPixels);
14258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (!mCalledSuper) {
14268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            throw new IllegalStateException(
14278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    "onPageScrolled did not call superclass implementation");
14288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
14294783095cc69fa85e484132337526c94d42d41c43Adam Powell        return true;
14308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
14318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
14338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * This method will be invoked when the current page is scrolled, either as part
14348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
14358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * If you override this method you must call through to the superclass implementation
14368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled
14378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * returns.
14388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
14398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param position Position index of the first page currently being displayed.
14408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *                 Page position+1 will be visible if positionOffset is nonzero.
14418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param offset Value from [0, 1) indicating the offset from the page at position.
14428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param offsetPixels Value in pixels indicating the offset from position.
14438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
14448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected void onPageScrolled(int position, float offset, int offsetPixels) {
14458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        // Offset any decor views if needed - keep them on-screen at all times.
14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mDecorChildCount > 0) {
14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int scrollX = getScrollX();
14488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            int paddingLeft = getPaddingLeft();
14498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            int paddingRight = getPaddingRight();
14508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int width = getWidth();
14518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int childCount = getChildCount();
14528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            for (int i = 0; i < childCount; i++) {
14538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final View child = getChildAt(i);
14548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
14558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (!lp.isDecor) continue;
14568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
14588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childLeft = 0;
14598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                switch (hgrav) {
14608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    default:
14618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = paddingLeft;
14628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
14638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.LEFT:
14648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = paddingLeft;
14658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        paddingLeft += child.getWidth();
14668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
14678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.CENTER_HORIZONTAL:
14688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
14698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                paddingLeft);
14708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
14718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.RIGHT:
14728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = width - paddingRight - child.getMeasuredWidth();
14738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        paddingRight += child.getMeasuredWidth();
14748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
14758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
14768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                childLeft += scrollX;
14778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final int childOffset = childLeft - child.getLeft();
14798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (childOffset != 0) {
14808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    child.offsetLeftAndRight(childOffset);
14818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
14828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
14838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
14848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mOnPageChangeListener != null) {
14868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);
14878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
14888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mInternalPageChangeListener != null) {
14898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);
14908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
14918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCalledSuper = true;
14928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
14938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
149447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    private void completeScroll() {
1495cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham        boolean needPopulate = mScrolling;
1496cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham        if (needPopulate) {
14974c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // Done with scroll, no longer want to cache view drawing.
14984c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            setScrollingCacheEnabled(false);
1499d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mScroller.abortAnimation();
1500d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int oldX = getScrollX();
1501d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int oldY = getScrollY();
1502d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int x = mScroller.getCurrX();
1503d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int y = mScroller.getCurrY();
1504d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (oldX != x || oldY != y) {
1505d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                scrollTo(x, y);
1506d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
150747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            setScrollState(SCROLL_STATE_IDLE);
15084c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
15093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        mPopulatePending = false;
15103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        mScrolling = false;
15114c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        for (int i=0; i<mItems.size(); i++) {
15124c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            ItemInfo ii = mItems.get(i);
15134c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            if (ii.scrolling) {
15144c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                needPopulate = true;
15154c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                ii.scrolling = false;
15164c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            }
15174c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
15184c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        if (needPopulate) {
15194c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            populate();
1520d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1521d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1522d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1523d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1524d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public boolean onInterceptTouchEvent(MotionEvent ev) {
1525d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        /*
1526d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * This method JUST determines whether we want to intercept the motion.
1527d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * If we return true, onMotionEvent will be called and we do the actual
1528d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * scrolling there.
1529d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         */
1530d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1531d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
1532d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1533d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Always take care of the touch gesture being complete.
1534d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
1535d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Release the drag.
1536d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (DEBUG) Log.v(TAG, "Intercept done!");
1537d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mIsBeingDragged = false;
1538d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mIsUnableToDrag = false;
1539d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mActivePointerId = INVALID_POINTER;
15403ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            if (mVelocityTracker != null) {
15413ce9274ccb8034c1787415c77307bbda36071bddAdam Powell                mVelocityTracker.recycle();
15423ce9274ccb8034c1787415c77307bbda36071bddAdam Powell                mVelocityTracker = null;
15433ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            }
1544d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return false;
1545d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1546d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1547d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Nothing more to do here if we have decided whether or not we
1548d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // are dragging.
1549d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (action != MotionEvent.ACTION_DOWN) {
1550d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mIsBeingDragged) {
1551d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Intercept returning true!");
1552d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return true;
1553d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1554d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mIsUnableToDrag) {
1555d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Intercept returning false!");
1556d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return false;
1557d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1558d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1559d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1560d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        switch (action) {
1561d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_MOVE: {
1562d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1563d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
1564d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * whether the user has moved far enough from his original down touch.
1565d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 */
1566d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1567d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1568d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                * Locally do absolute value. mLastMotionY is set to the y value
1569d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                * of the down event.
1570d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                */
1571d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int activePointerId = mActivePointerId;
1572d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (activePointerId == INVALID_POINTER) {
1573d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    // If we don't have a valid id, the touch down wasn't on content.
1574d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    break;
1575d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1576d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1577d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
1578d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float x = MotionEventCompat.getX(ev, pointerIndex);
157947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                final float dx = x - mLastMotionX;
158047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                final float xDiff = Math.abs(dx);
1581d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float y = MotionEventCompat.getY(ev, pointerIndex);
158247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                final float yDiff = Math.abs(y - mLastMotionY);
1583d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
1584bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
1585560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                if (canScroll(this, false, (int) dx, (int) x, (int) y)) {
1586bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    // Nested view has scrollable area under this point. Let it be handled there.
1587bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    mInitialMotionX = mLastMotionX = x;
1588bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    mLastMotionY = y;
1589b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                    mIsUnableToDrag = true;
1590bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    return false;
1591bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                }
1592d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (xDiff > mTouchSlop && xDiff > yDiff) {
1593d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    if (DEBUG) Log.v(TAG, "Starting drag!");
1594d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mIsBeingDragged = true;
159547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    setScrollState(SCROLL_STATE_DRAGGING);
1596d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mLastMotionX = x;
1597d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    setScrollingCacheEnabled(true);
1598d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                } else {
1599d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    if (yDiff > mTouchSlop) {
1600d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        // The finger has moved enough in the vertical
1601d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        // direction to be counted as a drag...  abort
1602d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        // any attempt to drag horizontally, to work correctly
1603d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        // with children that have scrolling containers.
1604d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        if (DEBUG) Log.v(TAG, "Starting unable to drag!");
1605d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        mIsUnableToDrag = true;
1606d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    }
1607d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1608d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1609d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1610d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1611d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_DOWN: {
1612d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1613d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * Remember location of down touch.
1614d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * ACTION_DOWN always refers to pointer index 0.
1615d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 */
1616d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = mInitialMotionX = ev.getX();
1617d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionY = ev.getY();
1618d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
1619b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                mIsUnableToDrag = false;
1620d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1621b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                if (mScrollState == SCROLL_STATE_SETTLING &&
1622b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                        Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
162347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    // Let the user 'catch' the pager as it animates.
162447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    mIsBeingDragged = true;
162547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    setScrollState(SCROLL_STATE_DRAGGING);
162647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                } else {
162747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    completeScroll();
162847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    mIsBeingDragged = false;
162947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                }
1630d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1631d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
1632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        + " mIsBeingDragged=" + mIsBeingDragged
1633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        + "mIsUnableToDrag=" + mIsUnableToDrag);
1634d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1635d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1636d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1637d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_UP:
1638d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                onSecondaryPointerUp(ev);
1639d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1640d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1641d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
16423ce9274ccb8034c1787415c77307bbda36071bddAdam Powell        if (!mIsBeingDragged) {
16433ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            // Track the velocity as long as we aren't dragging.
16443ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            // Once we start a real drag we will track in onTouchEvent.
16453ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            if (mVelocityTracker == null) {
16463ce9274ccb8034c1787415c77307bbda36071bddAdam Powell                mVelocityTracker = VelocityTracker.obtain();
16473ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            }
16483ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            mVelocityTracker.addMovement(ev);
16493ce9274ccb8034c1787415c77307bbda36071bddAdam Powell        }
16503ce9274ccb8034c1787415c77307bbda36071bddAdam Powell
1651d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        /*
16523ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         * The only time we want to intercept motion events is if we are in the
16533ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         * drag mode.
16543ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         */
1655d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return mIsBeingDragged;
1656d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1657d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1658d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1659d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public boolean onTouchEvent(MotionEvent ev) {
166069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mFakeDragging) {
166169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // A fake drag is in progress already, ignore this real one
166269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // but still eat the touch events.
166369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // (It is likely that the user is multi-touching the screen.)
166469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            return true;
166569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
1666d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1667d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
1668d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Don't handle edge touches immediately -- they may actually belong to one of our
1669d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // descendants.
1670d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return false;
1671d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1672d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
16733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (mAdapter == null || mAdapter.getCount() == 0) {
16743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // Nothing to present or scroll; nothing to touch.
16753661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            return false;
16763661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
16773661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
1678d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mVelocityTracker == null) {
1679d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker = VelocityTracker.obtain();
1680d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1681d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mVelocityTracker.addMovement(ev);
1682d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1683d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int action = ev.getAction();
1684560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        boolean needsInvalidate = false;
1685d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1686d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        switch (action & MotionEventCompat.ACTION_MASK) {
1687d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_DOWN: {
1688d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1689d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * If being flinged and user touches, stop the fling. isFinished
1690d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * will be false if being flinged.
1691d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 */
169247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                completeScroll();
1693d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1694d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                // Remember where the motion event started
1695d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = mInitialMotionX = ev.getX();
1696d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
1697d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1698d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1699d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_MOVE:
17003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (!mIsBeingDragged) {
17013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
17023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final float x = MotionEventCompat.getX(ev, pointerIndex);
170347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    final float xDiff = Math.abs(x - mLastMotionX);
17043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final float y = MotionEventCompat.getY(ev, pointerIndex);
170547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    final float yDiff = Math.abs(y - mLastMotionY);
17063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
17073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    if (xDiff > mTouchSlop && xDiff > yDiff) {
17083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        if (DEBUG) Log.v(TAG, "Starting drag!");
17093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        mIsBeingDragged = true;
17103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        mLastMotionX = x;
171147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                        setScrollState(SCROLL_STATE_DRAGGING);
17123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        setScrollingCacheEnabled(true);
17133661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    }
17143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
171531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                // Not else! Note that mIsBeingDragged can be set above.
1716d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
1717d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    // Scroll to follow the motion event
1718d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final int activePointerIndex = MotionEventCompat.findPointerIndex(
1719d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                            ev, mActivePointerId);
1720d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final float x = MotionEventCompat.getX(ev, activePointerIndex);
172147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    final float deltaX = mLastMotionX - x;
1722d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mLastMotionX = x;
1723560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                    float oldScrollX = getScrollX();
1724560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                    float scrollX = oldScrollX + deltaX;
17253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final int width = getWidth();
172647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
1727a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    float leftBound = width * mFirstOffset;
1728a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    float rightBound = width * mLastOffset;
1729a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    boolean leftAbsolute = true;
1730a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    boolean rightAbsolute = true;
1731a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1732a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final ItemInfo firstItem = mItems.get(0);
1733a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final ItemInfo lastItem = mItems.get(mItems.size() - 1);
1734a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (firstItem.position != 0) {
1735a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        leftAbsolute = false;
1736a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        leftBound = firstItem.offset * width;
1737a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1738a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lastItem.position != mAdapter.getCount() - 1) {
1739a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        rightAbsolute = false;
1740a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        rightBound = lastItem.offset * width;
1741a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1742a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
174347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    if (scrollX < leftBound) {
1744a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (leftAbsolute) {
1745a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            float over = leftBound - scrollX;
1746a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width);
1747560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                        }
174847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                        scrollX = leftBound;
174947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    } else if (scrollX > rightBound) {
1750a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (rightAbsolute) {
1751560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                            float over = scrollX - rightBound;
1752a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            needsInvalidate = mRightEdge.onPull(Math.abs(over) / width);
1753560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                        }
175447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                        scrollX = rightBound;
1755d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    }
175647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    // Don't lose the rounded component
175747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    mLastMotionX += scrollX - (int) scrollX;
175847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    scrollTo((int) scrollX, getScrollY());
17598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    pageScrolled((int) scrollX);
1760d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1761d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1762d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_UP:
1763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
1764d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final VelocityTracker velocityTracker = mVelocityTracker;
1765d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
17661cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
1767d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                            velocityTracker, mActivePointerId);
1768d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mPopulatePending = true;
1769a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int width = getWidth();
17701cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    final int scrollX = getScrollX();
1771a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final ItemInfo ii = infoForCurrentScrollPosition();
1772a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int currentPage = ii.position;
1773a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
1774035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final int activePointerIndex =
1775035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                            MotionEventCompat.findPointerIndex(ev, mActivePointerId);
1776035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final float x = MotionEventCompat.getX(ev, activePointerIndex);
1777035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final int totalDelta = (int) (x - mInitialMotionX);
1778035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
1779035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                            totalDelta);
17801cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    setCurrentItemInternal(nextPage, true, true, initialVelocity);
1781d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mActivePointerId = INVALID_POINTER;
1783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    endDrag();
1784560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_CANCEL:
1788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
1789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    setCurrentItemInternal(mCurItem, true, true);
1790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mActivePointerId = INVALID_POINTER;
1791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    endDrag();
1792560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
1793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_DOWN: {
1796d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int index = MotionEventCompat.getActionIndex(ev);
1797d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float x = MotionEventCompat.getX(ev, index);
1798d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = x;
1799d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, index);
1800d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1801d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_UP:
1803d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                onSecondaryPointerUp(ev);
1804d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = MotionEventCompat.getX(ev,
1805d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        MotionEventCompat.findPointerIndex(ev, mActivePointerId));
1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1808560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (needsInvalidate) {
1809b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
1810560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
1811d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return true;
1812d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1813d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1814a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    /**
1815a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * @return Info about the page at the current scroll position.
1816a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     *         This can be synthetic for a missing middle page; the 'object' field can be null.
1817a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     */
1818a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private ItemInfo infoForCurrentScrollPosition() {
1819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int width = getWidth();
1820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0;
1821a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
1822a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int lastPos = -1;
1823a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float lastOffset = 0.f;
1824a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float lastWidth = 0.f;
1825a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        boolean first = true;
1826a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1827ad079a869adf67a87a2721342de27970a3ba1844Adam Powell        ItemInfo lastItem = null;
1828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < mItems.size(); i++) {
1829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(i);
1830a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float offset;
1831a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (!first && ii.position != lastPos + 1) {
1832a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                // Create a synthetic item for a missing page.
1833a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii = mTempItem;
1834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.offset = lastOffset + lastWidth + marginOffset;
1835a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.position = lastPos + 1;
1836a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.widthFactor = mAdapter.getPageWidth(ii.position);
1837a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                i--;
1838a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset = ii.offset;
1840a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1841a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float leftBound = offset - 0.0001f;
1842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float rightBound = offset + ii.widthFactor + marginOffset + 0.0001f;
1843ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            if (first || scrollOffset >= leftBound) {
1844ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                if (scrollOffset < rightBound || i == mItems.size() - 1) {
1845ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                    return ii;
1846ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                }
1847ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            } else {
1848ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                return lastItem;
1849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            first = false;
1851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastPos = ii.position;
1852a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastOffset = offset;
1853a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastWidth = ii.widthFactor;
1854ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            lastItem = ii;
1855a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1857ad079a869adf67a87a2721342de27970a3ba1844Adam Powell        return lastItem;
1858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
1859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1860035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
1861035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        int targetPage;
1862035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
1863035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            targetPage = velocity > 0 ? currentPage : currentPage + 1;
1864035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        } else {
1865035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            targetPage = (int) (currentPage + pageOffset + 0.5f);
1866035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        }
1867035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell
1868a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mItems.size() > 0) {
1869a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo firstItem = mItems.get(0);
1870a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo lastItem = mItems.get(mItems.size() - 1);
1871a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1872a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Only let the user target pages we have items for
1873a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
1874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1875a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1876035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        return targetPage;
1877035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    }
1878035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell
1879560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    @Override
1880560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    public void draw(Canvas canvas) {
1881560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        super.draw(canvas);
1882560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        boolean needsInvalidate = false;
1883560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1884560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        final int overScrollMode = ViewCompat.getOverScrollMode(this);
1885560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
1886560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS &&
1887560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                        mAdapter != null && mAdapter.getCount() > 1)) {
1888560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            if (!mLeftEdge.isFinished()) {
1889560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int restoreCount = canvas.save();
1890560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
1891a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final int width = getWidth();
1892560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1893560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.rotate(270);
1894a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                canvas.translate(-height + getPaddingTop(), mFirstOffset * width);
1895a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                mLeftEdge.setSize(height, width);
1896560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                needsInvalidate |= mLeftEdge.draw(canvas);
1897560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.restoreToCount(restoreCount);
1898560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            }
1899560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            if (!mRightEdge.isFinished()) {
1900560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int restoreCount = canvas.save();
1901560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int width = getWidth();
1902560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
1903560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1904560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.rotate(90);
1905a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width);
1906560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                mRightEdge.setSize(height, width);
1907560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                needsInvalidate |= mRightEdge.draw(canvas);
1908560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.restoreToCount(restoreCount);
1909560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            }
1910560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        } else {
1911560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            mLeftEdge.finish();
1912560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            mRightEdge.finish();
1913560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
1914560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1915560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (needsInvalidate) {
1916560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            // Keep animating
1917b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
1918560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
1919560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    }
1920560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1921329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
1922329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected void onDraw(Canvas canvas) {
1923329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        super.onDraw(canvas);
1924329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
1925a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Draw the margin drawable between pages if needed.
1926a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) {
1927329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            final int scrollX = getScrollX();
1928329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            final int width = getWidth();
1929a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float marginOffset = (float) mPageMargin / width;
1931a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int itemIndex = 0;
1932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(0);
1933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float offset = ii.offset;
1934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int itemCount = mItems.size();
1935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int firstPos = ii.position;
1936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int lastPos = mItems.get(itemCount - 1).position;
1937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int pos = firstPos; pos < lastPos; pos++) {
1938a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                while (pos > ii.position && itemIndex < itemCount) {
1939a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(++itemIndex);
1940a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1941a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
194223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                float drawAt;
1943a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (pos == ii.position) {
194423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                    drawAt = (ii.offset + ii.widthFactor) * width;
1945a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset = ii.offset + ii.widthFactor + marginOffset;
1946a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else {
1947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    float widthFactor = mAdapter.getPageWidth(pos);
194823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                    drawAt = (offset + widthFactor) * width;
1949a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset += widthFactor + marginOffset;
1950a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1951a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1952a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (drawAt + mPageMargin > scrollX) {
195323b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                    mMarginDrawable.setBounds((int) (drawAt - 0.5f), mTopPageBounds,
195423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                            (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds);
1955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    mMarginDrawable.draw(canvas);
1956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (drawAt > scrollX + width) {
1959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    break; // No more visible, no sense in continuing
1960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1961329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            }
1962329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
1963329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
1964329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
196569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
196669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Start a fake drag of the pager.
196769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
196869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager
196969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * with the touch scrolling of another view, while still letting the ViewPager
197069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.)
197169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call
197269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * {@link #endFakeDrag()} to complete the fake drag and fling as necessary.
197369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
197469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag
197569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * is already in progress, this method will return false.
197669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
197769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @return true if the fake drag began successfully, false if it could not be started.
197869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
197969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
198069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
198169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
198269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public boolean beginFakeDrag() {
198369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mIsBeingDragged) {
198469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            return false;
198569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
198669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragging = true;
198769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        setScrollState(SCROLL_STATE_DRAGGING);
198869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mInitialMotionX = mLastMotionX = 0;
198969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mVelocityTracker == null) {
199069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            mVelocityTracker = VelocityTracker.obtain();
199169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        } else {
199269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            mVelocityTracker.clear();
199369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
199469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final long time = SystemClock.uptimeMillis();
199569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0);
199669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mVelocityTracker.addMovement(ev);
199769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        ev.recycle();
199869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragBeginTime = time;
199969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        return true;
200069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
200169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
200269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
200369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * End a fake drag of the pager.
200469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
200569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
200669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
200769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
200869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public void endFakeDrag() {
200969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (!mFakeDragging) {
201069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
201169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
201269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
201369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final VelocityTracker velocityTracker = mVelocityTracker;
201469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
20150f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell        int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
201669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell                velocityTracker, mActivePointerId);
201769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mPopulatePending = true;
2018a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int width = getWidth();
2019035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final int scrollX = getScrollX();
2020a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo ii = infoForCurrentScrollPosition();
2021a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int currentPage = ii.position;
2022a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
2023a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int totalDelta = (int) (mLastMotionX - mInitialMotionX);
2024a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
2025a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                totalDelta);
2026035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        setCurrentItemInternal(nextPage, true, true, initialVelocity);
202769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        endDrag();
202869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
202969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragging = false;
203069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
203169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
203269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
203369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first.
203469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
203569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @param xOffset Offset in pixels to drag by.
203669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
203769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
203869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
203969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public void fakeDragBy(float xOffset) {
204069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (!mFakeDragging) {
204169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
204269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
204369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
204469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mLastMotionX += xOffset;
2045a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2046a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float oldScrollX = getScrollX();
20470f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell        float scrollX = oldScrollX - xOffset;
204869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final int width = getWidth();
204969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
2050a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float leftBound = width * mFirstOffset;
2051a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float rightBound = width * mLastOffset;
2052a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2053a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo firstItem = mItems.get(0);
2054a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
2055a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (firstItem.position != 0) {
2056a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            leftBound = firstItem.offset * width;
2057a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
2058a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (lastItem.position != mAdapter.getCount() - 1) {
2059a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            rightBound = lastItem.offset * width;
2060a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
2061a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
206269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (scrollX < leftBound) {
206369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            scrollX = leftBound;
206469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        } else if (scrollX > rightBound) {
206569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            scrollX = rightBound;
206669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
206769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        // Don't lose the rounded component
206869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mLastMotionX += scrollX - (int) scrollX;
206969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        scrollTo((int) scrollX, getScrollY());
20708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        pageScrolled((int) scrollX);
207169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
207269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        // Synthesize an event for the VelocityTracker.
207369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final long time = SystemClock.uptimeMillis();
207469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE,
207569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell                mLastMotionX, 0, 0);
207669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mVelocityTracker.addMovement(ev);
207769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        ev.recycle();
207869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
207969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
208069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
208169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Returns true if a fake drag is in progress.
208269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
208369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @return true if currently in a fake drag, false otherwise.
208469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
208569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
208669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
208769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
208869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
208969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public boolean isFakeDragging() {
209069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        return mFakeDragging;
209169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
209269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
2093d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void onSecondaryPointerUp(MotionEvent ev) {
2094d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int pointerIndex = MotionEventCompat.getActionIndex(ev);
2095d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
2096d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (pointerId == mActivePointerId) {
2097d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // This was our active pointer going up. Choose a new
2098d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // active pointer and adjust accordingly.
2099d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
2100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);
2101d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
2102d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mVelocityTracker != null) {
2103d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mVelocityTracker.clear();
2104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
2105d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2106d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
2107d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2108d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void endDrag() {
2109d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mIsBeingDragged = false;
2110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mIsUnableToDrag = false;
2111d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2112d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mVelocityTracker != null) {
2113d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker.recycle();
2114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker = null;
2115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2116d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
2117d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2118d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void setScrollingCacheEnabled(boolean enabled) {
2119d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mScrollingCacheEnabled != enabled) {
2120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mScrollingCacheEnabled = enabled;
2121d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (USE_CACHE) {
2122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int size = getChildCount();
2123d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                for (int i = 0; i < size; ++i) {
2124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final View child = getChildAt(i);
2125d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    if (child.getVisibility() != GONE) {
2126d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        child.setDrawingCacheEnabled(enabled);
2127d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    }
2128d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
2129d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
2130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2131d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
21323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2133bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell    /**
2134cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * Tests scrollability within child views of v given a delta of dx.
2135bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     *
2136bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param v View to test for horizontal scrollability
2137bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
2138bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     *               or just its children (false).
2139bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param dx Delta scrolled in pixels
2140cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param x X coordinate of the active touch point
2141bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param y Y coordinate of the active touch point
2142cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @return true if child views of v can be scrolled by delta of dx.
2143bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     */
2144cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
2145bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        if (v instanceof ViewGroup) {
2146bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final ViewGroup group = (ViewGroup) v;
2147bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int scrollX = v.getScrollX();
2148bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int scrollY = v.getScrollY();
2149bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int count = group.getChildCount();
2150bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            // Count backwards - let topmost views consume scroll distance first.
2151bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            for (int i = count - 1; i >= 0; i--) {
2152bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                // TODO: Add versioned support here for transformed views.
2153bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                // This will not work for transformed views in Honeycomb+
2154bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                final View child = group.getChildAt(i);
2155bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
2156bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
2157bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
2158bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                                y + scrollY - child.getTop())) {
2159bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    return true;
2160bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                }
2161bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            }
2162bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        }
2163bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
2164bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        return checkV && ViewCompat.canScrollHorizontally(v, -dx);
2165bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell    }
2166bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
2167481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    @Override
21682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean dispatchKeyEvent(KeyEvent event) {
21692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // Let the focused view and/or our descendants get the key first
21702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
21712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
21722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
21732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
21742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * You can call this function yourself to have the scroll view perform
21752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * scrolling from a key event, just as if the event had been dispatched to
21762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * it by the view hierarchy.
21772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     *
21782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * @param event The key event to execute.
21792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * @return Return true if the event was handled, else false.
21802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
21812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean executeKeyEvent(KeyEvent event) {
21822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        boolean handled = false;
21832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (event.getAction() == KeyEvent.ACTION_DOWN) {
21842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            switch (event.getKeyCode()) {
21852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_DPAD_LEFT:
21862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = arrowScroll(FOCUS_LEFT);
21872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
21882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_DPAD_RIGHT:
21892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = arrowScroll(FOCUS_RIGHT);
21902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
21912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_TAB:
21925de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                    if (Build.VERSION.SDK_INT >= 11) {
21935de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD
21945de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        // before Android 3.0. Ignore the tab key on those devices.
21955de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        if (KeyEventCompat.hasNoModifiers(event)) {
21965de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                            handled = arrowScroll(FOCUS_FORWARD);
21975de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {
21985de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                            handled = arrowScroll(FOCUS_BACKWARD);
21995de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        }
22002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
22012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
22022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
22032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return handled;
22052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
22062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean arrowScroll(int direction) {
22082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        View currentFocused = findFocus();
22092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (currentFocused == this) currentFocused = null;
22102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        boolean handled = false;
22122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,
22142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                direction);
22152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (nextFocused != null && nextFocused != currentFocused) {
22162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (direction == View.FOCUS_LEFT) {
22172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // If there is nothing to the left, or this is causing us to
22182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // jump to the right, then what we really want to do is page left.
22192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (currentFocused != null && nextFocused.getLeft() >= currentFocused.getLeft()) {
22202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = pageLeft();
22212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                } else {
22222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = nextFocused.requestFocus();
22232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
22242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            } else if (direction == View.FOCUS_RIGHT) {
22252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // If there is nothing to the right, or this is causing us to
22262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // jump to the left, then what we really want to do is page right.
22272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (currentFocused != null && nextFocused.getLeft() <= currentFocused.getLeft()) {
22282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = pageRight();
22292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                } else {
22302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = nextFocused.requestFocus();
22312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
22322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
22332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {
22342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Trying to move left and nothing there; try to page.
22352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            handled = pageLeft();
22362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {
22372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Trying to move right and nothing there; try to page.
22382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            handled = pageRight();
22392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (handled) {
22412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
22422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return handled;
22442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
22452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    boolean pageLeft() {
22472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (mCurItem > 0) {
22482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            setCurrentItem(mCurItem-1, true);
22492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return true;
22502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
22522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
22532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    boolean pageRight() {
2255218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) {
22562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            setCurrentItem(mCurItem+1, true);
22572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return true;
22582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
22602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
22612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
22632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be focusable.
22642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
22652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
22662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
22672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        final int focusableCount = views.size();
22682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        final int descendantFocusability = getDescendantFocusability();
22702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
22722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            for (int i = 0; i < getChildCount(); i++) {
22732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                final View child = getChildAt(i);
22742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (child.getVisibility() == VISIBLE) {
22752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    ItemInfo ii = infoForChild(child);
22762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (ii != null && ii.position == mCurItem) {
22772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        child.addFocusables(views, direction, focusableMode);
22782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
22792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
22802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
22812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // we add ourselves (if focusable) in all cases except for when we are
22842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
22852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // to avoid the focus search finding layouts when a more precise search
22862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // among the focusable children would be more interesting.
22872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (
22882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
22892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // No focusable descendants
22902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                (focusableCount == views.size())) {
22912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Note that we can't call the superclass here, because it will
22922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // add all views in.  So we need to do the same thing View does.
22932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (!isFocusable()) {
22942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return;
22952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
22962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE &&
22972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    isInTouchMode() && !isFocusableInTouchMode()) {
22982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return;
22992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
23002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (views != null) {
23012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                views.add(this);
23022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
23032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
23042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
23052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
23072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be touchable.
23082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
23092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
23102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public void addTouchables(ArrayList<View> views) {
23112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // Note that we don't call super.addTouchables(), which means that
23122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // we don't call View.addTouchables().  This is okay because a ViewPager
23132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // is itself not touchable.
23142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        for (int i = 0; i < getChildCount(); i++) {
23152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            final View child = getChildAt(i);
23162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (child.getVisibility() == VISIBLE) {
23172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                ItemInfo ii = infoForChild(child);
23182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (ii != null && ii.position == mCurItem) {
23192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    child.addTouchables(views);
23202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
23212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
23222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
23232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
23242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
23262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be focusable.
23272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
23282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
23292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    protected boolean onRequestFocusInDescendants(int direction,
23302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            Rect previouslyFocusedRect) {
23312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int index;
23322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int increment;
23332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int end;
23342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int count = getChildCount();
23352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if ((direction & FOCUS_FORWARD) != 0) {
23362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            index = 0;
23372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            increment = 1;
23382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            end = count;
23392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else {
23402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            index = count - 1;
23412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            increment = -1;
23422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            end = -1;
23432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
23442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        for (int i = index; i != end; i += increment) {
23452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            View child = getChildAt(i);
23462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (child.getVisibility() == VISIBLE) {
23472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                ItemInfo ii = infoForChild(child);
23482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (ii != null && ii.position == mCurItem) {
23492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (child.requestFocus(direction, previouslyFocusedRect)) {
23502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        return true;
23512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
23522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
23532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
2354481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        }
23552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
2356481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    }
2357481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2358481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    @Override
2359481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
2360481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        // ViewPagers should only report accessibility info for the current page,
2361481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        // otherwise things get very confusing.
2362481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2363481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        // TODO: Should this note something about the paging container?
2364481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2365481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        final int childCount = getChildCount();
2366481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        for (int i = 0; i < childCount; i++) {
2367481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            final View child = getChildAt(i);
2368481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            if (child.getVisibility() == VISIBLE) {
2369481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                final ItemInfo ii = infoForChild(child);
2370481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                if (ii != null && ii.position == mCurItem &&
2371481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                        child.dispatchPopulateAccessibilityEvent(event)) {
2372481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                    return true;
2373481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                }
2374481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            }
2375481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        }
2376481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2377481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        return false;
2378481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    }
2379481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
23808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
23818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
23828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return new LayoutParams();
23838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
23848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
23858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
23868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
23878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return generateDefaultLayoutParams();
23888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
23898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
23908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
23918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
23928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return p instanceof LayoutParams && super.checkLayoutParams(p);
23938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
23948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
23958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
23968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
23971ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        return new LayoutParams(getContext(), attrs);
23988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
23998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
24008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private class PagerObserver extends DataSetObserver {
24018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        @Override
24028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onChanged() {
24038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            dataSetChanged();
24048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
24053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
24068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onInvalidated() {
24073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            dataSetChanged();
24083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
24093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
24108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
24117dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn    /**
24127dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * Layout parameters that should be supplied for views added to a
24137dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * ViewPager.
24147dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     */
24158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public static class LayoutParams extends ViewGroup.LayoutParams {
24168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        /**
24178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * true if this view is a decoration on the pager itself and not
24188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * a view supplied by the adapter.
24198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         */
24208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public boolean isDecor;
24218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2422a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
24233d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn         * Gravity setting for use on decor views only:
24247dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn         * Where to position the view page within the overall ViewPager
24257dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn         * container; constants are defined in {@link android.view.Gravity}.
2426a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
24278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public int gravity;
24288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2429a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
2430a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * Width as a 0-1 multiplier of the measured pager width
2431a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
2432a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        public float widthFactor = 0.f;
2433a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2434a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
2435a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * true if this view was added during layout and needs to be measured
2436a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * before being positioned.
2437a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
2438a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        public boolean needsMeasure;
2439a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
24408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public LayoutParams() {
24418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            super(FILL_PARENT, FILL_PARENT);
24428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
24438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
24448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public LayoutParams(Context context, AttributeSet attrs) {
24458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            super(context, attrs);
24468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
24478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
2448a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            gravity = a.getInteger(0, Gravity.TOP);
24498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            a.recycle();
24508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
24518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
2452d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn}
2453