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;
20199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powellimport android.content.res.Resources;
218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.content.res.TypedArray;
228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.database.DataSetObserver;
23560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.graphics.Canvas;
24481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.graphics.Rect;
25329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powellimport android.graphics.drawable.Drawable;
265de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powellimport android.os.Build;
2725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.os.Bundle;
28d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcel;
29d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcelable;
3069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powellimport android.os.SystemClock;
315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompat;
325c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompatCreatorCallbacks;
33109e561bfa6720a7043a28dc265297d915170954Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityEventCompat;
3425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
35109e561bfa6720a7043a28dc265297d915170954Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityRecordCompat;
36560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.support.v4.widget.EdgeEffectCompat;
37d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.AttributeSet;
38d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.Log;
392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.FocusFinder;
408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.Gravity;
412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent;
42d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.MotionEvent;
432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.SoundEffectConstants;
44d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.VelocityTracker;
45d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.View;
46d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewConfiguration;
47d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewGroup;
48218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackbornimport android.view.ViewParent;
49481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.view.accessibility.AccessibilityEvent;
501cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powellimport android.view.animation.Interpolator;
51d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.widget.Scroller;
52d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
538a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powellimport java.lang.reflect.Method;
54d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport java.util.ArrayList;
5566c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Collections;
5666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Comparator;
57d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
58d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/**
59d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Layout manager that allows the user to flip left and right
605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * through pages of data.  You supply an implementation of a
615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * {@link PagerAdapter} to generate the pages that the view shows.
625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn *
635c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * <p>Note this class is currently under early design and
645c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * development.  The API will likely change in later updates of
655c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * the compatibility library, requiring changes to the source code
665c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * of apps when they are compiled against the newer version.</p>
677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment},
697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which is a convenient way to supply and manage the lifecycle of each page.
707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * There are standard adapters implemented for using fragments with the ViewPager,
717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which cover the most common use cases.  These are
7233586fb4d8b42d7c65240ffcc269fe10e682b309Scott Main * {@link android.support.v4.app.FragmentPagerAdapter} and
7333586fb4d8b42d7c65240ffcc269fe10e682b309Scott Main * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these
747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * classes have simple code showing how to build a full user interface
757dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with them.
767dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
777dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is a more complicated example of ViewPager, using it in conjuction
787dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with {@link android.app.ActionBar} tabs.  You can find other examples of using
797dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code.
807dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
817dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
827dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *      complete}
83d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */
84ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackbornpublic class ViewPager extends ViewGroup {
853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private static final String TAG = "ViewPager";
86d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final boolean DEBUG = false;
87d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
88d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final boolean USE_CACHE = false;
89d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
9029a6184d74279156a9297dc67398712fb047fdc0Adam Powell    private static final int DEFAULT_OFFSCREEN_PAGES = 1;
911cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    private static final int MAX_SETTLE_DURATION = 600; // ms
92035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
9329a6184d74279156a9297dc67398712fb047fdc0Adam Powell
948f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private static final int DEFAULT_GUTTER_SIZE = 16; // dips
958f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell
9616991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell    private static final int MIN_FLING_VELOCITY = 400; // dips
9716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell
988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private static final int[] LAYOUT_ATTRS = new int[] {
998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        android.R.attr.layout_gravity
1008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    };
1018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
102199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell    /**
103199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell     * Used to track what the expected number of items in the adapter should be.
104199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell     * If the app changes this when we don't expect it, we'll throw a big obnoxious exception.
105199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell     */
106199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell    private int mExpectedAdapterCount;
107199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell
108d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    static class ItemInfo {
109ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        Object object;
110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int position;
1114c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        boolean scrolling;
112a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float widthFactor;
113a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float offset;
114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
11666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham    private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){
11766c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        @Override
11866c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        public int compare(ItemInfo lhs, ItemInfo rhs) {
11966c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham            return lhs.position - rhs.position;
120a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    };
12266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham
1231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    private static final Interpolator sInterpolator = new Interpolator() {
1241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        public float getInterpolation(float t) {
1251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell            t -= 1.0f;
126035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            return t * t * t * t * t + 1.0f;
1271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        }
1281cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    };
1291cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
131a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private final ItemInfo mTempItem = new ItemInfo();
132d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
133dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell    private final Rect mTempRect = new Rect();
134dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell
135ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    private PagerAdapter mAdapter;
1363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private int mCurItem;   // Index of currently displayed page.
137d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mRestoredCurItem = -1;
138ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    private Parcelable mRestoredAdapterState = null;
1395c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private ClassLoader mRestoredClassLoader = null;
140d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private Scroller mScroller;
1418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private PagerObserver mObserver;
142d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
143329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private int mPageMargin;
144329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private Drawable mMarginDrawable;
1458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mTopPageBounds;
1468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mBottomPageBounds;
147329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // Offsets of the first and last items, if known.
149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // Set during population, used to determine if we are at the beginning
150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // or end of the pager data set during touch scrolling.
151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private float mFirstOffset = -Float.MAX_VALUE;
152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private float mLastOffset = Float.MAX_VALUE;
153a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mChildWidthMeasureSpec;
155d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mChildHeightMeasureSpec;
156d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mInLayout;
157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mScrollingCacheEnabled;
159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mPopulatePending;
16129a6184d74279156a9297dc67398712fb047fdc0Adam Powell    private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;
162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mIsBeingDragged;
164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mIsUnableToDrag;
1658f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private boolean mIgnoreGutter;
1668f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private int mDefaultGutterSize;
1678f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private int mGutterSize;
168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mTouchSlop;
169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Position of the last motion event.
171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private float mLastMotionX;
173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private float mLastMotionY;
17416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell    private float mInitialMotionX;
17516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell    private float mInitialMotionY;
176d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
177d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * ID of the active pointer. This is used to retain consistency during
178d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * drags/flings if multiple pointers are used.
179d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
180d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mActivePointerId = INVALID_POINTER;
181d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
182d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Sentinel value for no current active pointer.
183d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Used by {@link #mActivePointerId}.
184d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
185d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final int INVALID_POINTER = -1;
186d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
187d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
188d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Determines speed during touch scrolling
189d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
190d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private VelocityTracker mVelocityTracker;
191d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mMinimumVelocity;
192d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mMaximumVelocity;
193035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private int mFlingDistance;
194b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    private int mCloseEnough;
195b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell
196b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // If the pager is at least this close to its final position, complete the scroll
197b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // on touch down and let the user interact with the content inside instead of
198b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // "catching" the flinging pager.
199b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    private static final int CLOSE_ENOUGH = 2; // dp
200d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
20169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    private boolean mFakeDragging;
20269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    private long mFakeDragBeginTime;
20369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
204560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    private EdgeEffectCompat mLeftEdge;
205560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    private EdgeEffectCompat mRightEdge;
206560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
20797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    private boolean mFirstLayout = true;
208a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private boolean mNeedCalculatePageOffsets = false;
2098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private boolean mCalledSuper;
2108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mDecorChildCount;
21197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell
2123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private OnPageChangeListener mOnPageChangeListener;
2138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private OnPageChangeListener mInternalPageChangeListener;
2148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private OnAdapterChangeListener mAdapterChangeListener;
2158a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    private PageTransformer mPageTransformer;
2168a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    private Method mSetChildrenDrawingOrderEnabled;
2173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2187e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell    private static final int DRAW_ORDER_DEFAULT = 0;
2197e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell    private static final int DRAW_ORDER_FORWARD = 1;
2207e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell    private static final int DRAW_ORDER_REVERSE = 2;
2217e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell    private int mDrawingOrder;
2227e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell    private ArrayList<View> mDrawingOrderedChildren;
2237e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell    private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator();
2247e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell
2253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    /**
22647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is in an idle, settled state. The current page
22747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * is fully in view and no animation is in progress.
22847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
22947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_IDLE = 0;
23047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
23147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
23247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is currently being dragged by the user.
23347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
23447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_DRAGGING = 1;
23547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
23647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
23747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is in the process of settling to a final position.
23847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
23947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_SETTLING = 2;
24047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
24171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio    private final Runnable mEndScrollRunnable = new Runnable() {
24271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio        public void run() {
24371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio            setScrollState(SCROLL_STATE_IDLE);
24471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio            populate();
24571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio        }
24671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio    };
24771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio
24847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    private int mScrollState = SCROLL_STATE_IDLE;
24947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
25047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
2513661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * Callback interface for responding to changing state of the selected page.
2523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     */
2533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public interface OnPageChangeListener {
25447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
2553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        /**
2563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * This method will be invoked when the current page is scrolled, either as part
2573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
2583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *
2593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param position Position index of the first page currently being displayed.
2603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *                 Page position+1 will be visible if positionOffset is nonzero.
2613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
2623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param positionOffsetPixels Value in pixels indicating the offset from position.
2633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         */
2643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
2653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        /**
26747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * This method will be invoked when a new page becomes selected. Animation is not
26847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * necessarily complete.
2693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *
2703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param position Position index of the new selected page.
2713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         */
2723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageSelected(int position);
27347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
27447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        /**
27547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * Called when the scroll state changes. Useful for discovering when the user
27647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * begins dragging, when the pager is automatically settling to the current page,
27747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * or when it is fully stopped/idle.
27847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         *
27947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @param state The new scroll state.
28047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_IDLE
28147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_DRAGGING
28247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_SETTLING
28347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         */
28447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        public void onPageScrollStateChanged(int state);
2853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
2863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    /**
2883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * Simple implementation of the {@link OnPageChangeListener} interface with stub
2893661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * implementations of each method. Extend this if you do not intend to override
2903661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * every method of {@link OnPageChangeListener}.
2913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     */
2923661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public static class SimpleOnPageChangeListener implements OnPageChangeListener {
2933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
2943661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
2953661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // This space for rent
2963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
2973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2983661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
2993661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageSelected(int position) {
3003661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // This space for rent
3013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
30247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
30347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        @Override
30447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        public void onPageScrollStateChanged(int state) {
30547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            // This space for rent
30647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
3073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
3083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
3098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
3108a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
3118a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * This offers an opportunity for the application to apply a custom transformation
3128a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * to the page views using animation properties.
3138a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     *
3148a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * <p>As property animation is only supported as of Android 3.0 and forward,
3158a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * setting a PageTransformer on a ViewPager on earlier platform versions will
3168a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * be ignored.</p>
3178a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     */
3188a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    public interface PageTransformer {
3198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        /**
3208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell         * Apply a property transformation to the given page.
3218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell         *
3228a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell         * @param page Apply the transformation to this page
3238a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell         * @param position Position of page relative to the current front-and-center
3248a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell         *                 position of the pager. 0 is front and center. 1 is one full
3258a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell         *                 page position to the right, and -1 is one page position to the left.
3268a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell         */
3278a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        public void transformPage(View page, float position);
3288a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    }
3298a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell
3308a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    /**
3318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Used internally to monitor when adapters are switched.
3328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
3338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    interface OnAdapterChangeListener {
3348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter);
3358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
3368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3371ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell    /**
3381ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     * Used internally to tag special types of child views that should be added as
3391ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     * pager decorations by default.
3401ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     */
3411ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell    interface Decor {}
3421ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell
343ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public ViewPager(Context context) {
344d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super(context);
34547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        initViewPager();
346d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
347d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
348ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public ViewPager(Context context, AttributeSet attrs) {
349d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super(context, attrs);
35047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        initViewPager();
351d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
352d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
35347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    void initViewPager() {
354d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        setWillNotDraw(false);
3552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
3562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        setFocusable(true);
357560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        final Context context = getContext();
3581cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        mScroller = new Scroller(context, sInterpolator);
3591cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        final ViewConfiguration configuration = ViewConfiguration.get(context);
36016991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell        final float density = context.getResources().getDisplayMetrics().density;
36116991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell
362d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
36316991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell        mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
364d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
365560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        mLeftEdge = new EdgeEffectCompat(context);
366560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        mRightEdge = new EdgeEffectCompat(context);
3671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
368035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
369b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell        mCloseEnough = (int) (CLOSE_ENOUGH * density);
3708f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);
37125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
37225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate());
37325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
37425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        if (ViewCompat.getImportantForAccessibility(this)
37525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
37625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            ViewCompat.setImportantForAccessibility(this,
37725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
37825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        }
379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
38171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio    @Override
38271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio    protected void onDetachedFromWindow() {
38371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio        removeCallbacks(mEndScrollRunnable);
38471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio        super.onDetachedFromWindow();
38571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio    }
38671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio
38747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    private void setScrollState(int newState) {
38847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        if (mScrollState == newState) {
38947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            return;
39047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
39147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
39247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        mScrollState = newState;
3938a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        if (mPageTransformer != null) {
3948a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            // PageTransformers can do complex things that benefit from hardware layers.
3958a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            enableLayers(newState != SCROLL_STATE_IDLE);
3968a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        }
39747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        if (mOnPageChangeListener != null) {
39847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            mOnPageChangeListener.onPageScrollStateChanged(newState);
39947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
40047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    }
40147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
4028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
4038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a PagerAdapter that will supply views for this pager as needed.
4048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
4058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param adapter Adapter to use
4068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
407ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public void setAdapter(PagerAdapter adapter) {
4083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (mAdapter != null) {
4098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapter.unregisterDataSetObserver(mObserver);
4100d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mAdapter.startUpdate(this);
4110d6d2990ddacd3f419879149137f09a30c061436Minh Pham            for (int i = 0; i < mItems.size(); i++) {
4120d6d2990ddacd3f419879149137f09a30c061436Minh Pham                final ItemInfo ii = mItems.get(i);
4130d6d2990ddacd3f419879149137f09a30c061436Minh Pham                mAdapter.destroyItem(this, ii.position, ii.object);
4140d6d2990ddacd3f419879149137f09a30c061436Minh Pham            }
4150d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mAdapter.finishUpdate(this);
4160d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mItems.clear();
417a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            removeNonDecorViews();
4180d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mCurItem = 0;
419871a68b5daafd810623d680207652f87eb2d11ccMinh Pham            scrollTo(0, 0);
4203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
4213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
4228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final PagerAdapter oldAdapter = mAdapter;
423d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mAdapter = adapter;
424199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell        mExpectedAdapterCount = 0;
425d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
426d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter != null) {
4273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (mObserver == null) {
4288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mObserver = new PagerObserver();
4293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
4308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapter.registerDataSetObserver(mObserver);
431d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mPopulatePending = false;
432fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            final boolean wasFirstLayout = mFirstLayout;
43391eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell            mFirstLayout = true;
434199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell            mExpectedAdapterCount = mAdapter.getCount();
435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mRestoredCurItem >= 0) {
4365c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
437d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                setCurrentItemInternal(mRestoredCurItem, false, true);
438d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mRestoredCurItem = -1;
439ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn                mRestoredAdapterState = null;
4405c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                mRestoredClassLoader = null;
441fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            } else if (!wasFirstLayout) {
442d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                populate();
443fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            } else {
444fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell                requestLayout();
445d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
446d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
4478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
4488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mAdapterChangeListener != null && oldAdapter != adapter) {
4498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
4508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
451d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
452d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
453a7aea206661d601755bfac4165092d9130cba2bcAdam Powell    private void removeNonDecorViews() {
454a7aea206661d601755bfac4165092d9130cba2bcAdam Powell        for (int i = 0; i < getChildCount(); i++) {
455a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            final View child = getChildAt(i);
456a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
457a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            if (!lp.isDecor) {
458a7aea206661d601755bfac4165092d9130cba2bcAdam Powell                removeViewAt(i);
459a7aea206661d601755bfac4165092d9130cba2bcAdam Powell                i--;
460a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            }
461a7aea206661d601755bfac4165092d9130cba2bcAdam Powell        }
462a7aea206661d601755bfac4165092d9130cba2bcAdam Powell    }
463a7aea206661d601755bfac4165092d9130cba2bcAdam Powell
4648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
4658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Retrieve the current adapter supplying pages.
4668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
4678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @return The currently registered PagerAdapter
4688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
469ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public PagerAdapter getAdapter() {
470d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return mAdapter;
471d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
472d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
4738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    void setOnAdapterChangeListener(OnAdapterChangeListener listener) {
4748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mAdapterChangeListener = listener;
4758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
4768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
477becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu    private int getClientWidth() {
478fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell        return getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
479becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu    }
480becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu
48197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    /**
48297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * Set the currently selected page. If the ViewPager has already been through its first
48391eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell     * layout with its current adapter there will be a smooth animated transition between
48491eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell     * the current item and the specified item.
48597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     *
48697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param item Item index to select
48797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     */
488d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void setCurrentItem(int item) {
489d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mPopulatePending = false;
49097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        setCurrentItemInternal(item, !mFirstLayout, false);
49197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    }
49297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell
49397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    /**
49497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * Set the currently selected page.
49597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     *
49697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param item Item index to select
49797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
49897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     */
49997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    public void setCurrentItem(int item, boolean smoothScroll) {
50097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mPopulatePending = false;
50197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        setCurrentItemInternal(item, smoothScroll, false);
502d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
503d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
504bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki    public int getCurrentItem() {
505bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki        return mCurItem;
506bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki    }
507bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki
508d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
5091cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        setCurrentItemInternal(item, smoothScroll, always, 0);
5101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
5111cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
5121cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
513d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter == null || mAdapter.getCount() <= 0) {
514d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
515d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
516d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
517d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (!always && mCurItem == item && mItems.size() != 0) {
518d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
519d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
520d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
5218d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell
522d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (item < 0) {
523d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            item = 0;
524d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else if (item >= mAdapter.getCount()) {
525d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            item = mAdapter.getCount() - 1;
526d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
52729a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int pageLimit = mOffscreenPageLimit;
52829a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
5294c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // We are doing a jump by more than one page.  To avoid
5304c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // glitches, we want to keep all current pages in the view
5314c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // until the scroll ends.
5324c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            for (int i=0; i<mItems.size(); i++) {
5334c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                mItems.get(i).scrolling = true;
5344c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            }
5354c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
53647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        final boolean dispatchSelected = mCurItem != item;
537fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell
538fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell        if (mFirstLayout) {
539fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            // We don't have any idea how big we are yet and shouldn't have any pages either.
540fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            // Just set things up and let the pending layout handle things.
541fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            mCurItem = item;
542fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            if (dispatchSelected && mOnPageChangeListener != null) {
543fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell                mOnPageChangeListener.onPageSelected(item);
544fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            }
545fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            if (dispatchSelected && mInternalPageChangeListener != null) {
546fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell                mInternalPageChangeListener.onPageSelected(item);
547fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            }
548fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            requestLayout();
549fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell        } else {
550fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            populate(item);
551fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell            scrollToItem(item, smoothScroll, velocity, dispatchSelected);
552fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell        }
553a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne    }
554a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne
555a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne    private void scrollToItem(int item, boolean smoothScroll, int velocity,
556a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne            boolean dispatchSelected) {
557a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo curInfo = infoForPosition(item);
55831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        int destX = 0;
55931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        if (curInfo != null) {
560becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu            final int width = getClientWidth();
56131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            destX = (int) (width * Math.max(mFirstOffset,
56231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                    Math.min(curInfo.offset, mLastOffset)));
56331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        }
564d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (smoothScroll) {
5651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell            smoothScrollTo(destX, 0, velocity);
56647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            if (dispatchSelected && mOnPageChangeListener != null) {
56747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                mOnPageChangeListener.onPageSelected(item);
56847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            }
5698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (dispatchSelected && mInternalPageChangeListener != null) {
5708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mInternalPageChangeListener.onPageSelected(item);
5718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
572d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
57347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            if (dispatchSelected && mOnPageChangeListener != null) {
5743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mOnPageChangeListener.onPageSelected(item);
5753661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
5768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (dispatchSelected && mInternalPageChangeListener != null) {
5778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mInternalPageChangeListener.onPageSelected(item);
5788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
57971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio            completeScroll(false);
580329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            scrollTo(destX, 0);
581c8c0fc23e8ff21166a7699e324426a6a7dc65806Chet Haase            pageScrolled(destX);
582d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
583d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
584d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
5858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
5868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a listener that will be invoked whenever the page changes or is incrementally
5878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * scrolled. See {@link OnPageChangeListener}.
5888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
5898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param listener Listener to set
5908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
5913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public void setOnPageChangeListener(OnPageChangeListener listener) {
5923661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        mOnPageChangeListener = listener;
5933661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
5943661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
595d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
5968a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * Set a {@link PageTransformer} that will be called for each attached page whenever
5978a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * the scroll position is changed. This allows the application to apply custom property
5988a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * transformations to each page, overriding the default sliding look and feel.
5998a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     *
6008a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist.
6018a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p>
6028a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     *
6038a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
6048a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     *                            to be drawn from last to first instead of first to last.
6058a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     * @param transformer PageTransformer that will modify each page's animation properties
6068a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell     */
6078a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
6088a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        if (Build.VERSION.SDK_INT >= 11) {
6097e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            final boolean hasTransformer = transformer != null;
6107e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
6118a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            mPageTransformer = transformer;
6127e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            setChildrenDrawingOrderEnabledCompat(hasTransformer);
6137e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            if (hasTransformer) {
6147e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell                mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
6157e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            } else {
6167e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell                mDrawingOrder = DRAW_ORDER_DEFAULT;
6177e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            }
6187e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            if (needsPopulate) populate();
6198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        }
6208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    }
6218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell
6228a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    void setChildrenDrawingOrderEnabledCompat(boolean enable) {
623f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell        if (Build.VERSION.SDK_INT >= 7) {
624f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            if (mSetChildrenDrawingOrderEnabled == null) {
625f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                try {
626f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                    mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod(
627f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                            "setChildrenDrawingOrderEnabled", new Class[] { Boolean.TYPE });
628f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                } catch (NoSuchMethodException e) {
629f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                    Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e);
630f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                }
631f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            }
6328a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            try {
633f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                mSetChildrenDrawingOrderEnabled.invoke(this, enable);
634f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            } catch (Exception e) {
635f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                Log.e(TAG, "Error changing children drawing order", e);
6368a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            }
6378a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        }
6388a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    }
6398a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell
6408a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    @Override
6418a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    protected int getChildDrawingOrder(int childCount, int i) {
6427e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i;
6437e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex;
6447e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        return result;
6458a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    }
6468a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell
6478a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    /**
6488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a separate OnPageChangeListener for internal use by the support library.
6498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
6508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param listener Listener to set
6518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @return The old listener that was set, if any.
6528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
6538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {
6548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        OnPageChangeListener oldListener = mInternalPageChangeListener;
6558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mInternalPageChangeListener = listener;
6568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return oldListener;
6578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
6588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
6598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
66029a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * Returns the number of pages that will be retained to either side of the
66129a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * current page in the view hierarchy in an idle state. Defaults to 1.
66229a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
66329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @return How many pages will be kept offscreen on either side
66429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @see #setOffscreenPageLimit(int)
66529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     */
66629a6184d74279156a9297dc67398712fb047fdc0Adam Powell    public int getOffscreenPageLimit() {
66729a6184d74279156a9297dc67398712fb047fdc0Adam Powell        return mOffscreenPageLimit;
66829a6184d74279156a9297dc67398712fb047fdc0Adam Powell    }
66929a6184d74279156a9297dc67398712fb047fdc0Adam Powell
67029a6184d74279156a9297dc67398712fb047fdc0Adam Powell    /**
67129a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * Set the number of pages that should be retained to either side of the
67229a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * current page in the view hierarchy in an idle state. Pages beyond this
67329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * limit will be recreated from the adapter when needed.
67429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
67529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * <p>This is offered as an optimization. If you know in advance the number
67629a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * of pages you will need to support or have lazy-loading mechanisms in place
67729a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * on your pages, tweaking this setting can have benefits in perceived smoothness
67829a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * of paging animations and interaction. If you have a small number of pages (3-4)
67929a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * that you can keep active all at once, less time will be spent in layout for
68029a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * newly created view subtrees as the user pages back and forth.</p>
68129a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
68229a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * <p>You should keep this limit low, especially if your pages have complex layouts.
68329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * This setting defaults to 1.</p>
68429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
68529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @param limit How many pages will be kept offscreen in an idle state.
68629a6184d74279156a9297dc67398712fb047fdc0Adam Powell     */
68729a6184d74279156a9297dc67398712fb047fdc0Adam Powell    public void setOffscreenPageLimit(int limit) {
68829a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (limit < DEFAULT_OFFSCREEN_PAGES) {
68929a6184d74279156a9297dc67398712fb047fdc0Adam Powell            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
69029a6184d74279156a9297dc67398712fb047fdc0Adam Powell                    DEFAULT_OFFSCREEN_PAGES);
69129a6184d74279156a9297dc67398712fb047fdc0Adam Powell            limit = DEFAULT_OFFSCREEN_PAGES;
69229a6184d74279156a9297dc67398712fb047fdc0Adam Powell        }
69329a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (limit != mOffscreenPageLimit) {
69429a6184d74279156a9297dc67398712fb047fdc0Adam Powell            mOffscreenPageLimit = limit;
69529a6184d74279156a9297dc67398712fb047fdc0Adam Powell            populate();
69629a6184d74279156a9297dc67398712fb047fdc0Adam Powell        }
69729a6184d74279156a9297dc67398712fb047fdc0Adam Powell    }
69829a6184d74279156a9297dc67398712fb047fdc0Adam Powell
69929a6184d74279156a9297dc67398712fb047fdc0Adam Powell    /**
700329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set the margin between pages.
701329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
702329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param marginPixels Distance between adjacent pages in pixels
703329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #getPageMargin()
704329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #setPageMarginDrawable(Drawable)
705329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #setPageMarginDrawable(int)
706329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
707329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMargin(int marginPixels) {
708329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final int oldMargin = mPageMargin;
709329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        mPageMargin = marginPixels;
710329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
711329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final int width = getWidth();
712329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        recomputeScrollPosition(width, width, marginPixels, oldMargin);
713329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
714329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        requestLayout();
715329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
716329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
717329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
718329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Return the margin between pages.
719329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
720329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @return The size of the margin in pixels
721329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
722329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public int getPageMargin() {
723329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        return mPageMargin;
724329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
725329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
726329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
727329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set a drawable that will be used to fill the margin between pages.
728329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
729329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param d Drawable to display between pages
730329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
731329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMarginDrawable(Drawable d) {
732329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        mMarginDrawable = d;
733329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        if (d != null) refreshDrawableState();
734329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        setWillNotDraw(d == null);
735329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        invalidate();
736329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
737329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
738329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
739329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set a drawable that will be used to fill the margin between pages.
740329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
741329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param resId Resource ID of a drawable to display between pages
742329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
743329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMarginDrawable(int resId) {
744329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        setPageMarginDrawable(getContext().getResources().getDrawable(resId));
745329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
746329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
747329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
748329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected boolean verifyDrawable(Drawable who) {
749329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        return super.verifyDrawable(who) || who == mMarginDrawable;
750329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
751329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
752329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
753329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected void drawableStateChanged() {
754329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        super.drawableStateChanged();
755329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final Drawable d = mMarginDrawable;
756329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        if (d != null && d.isStateful()) {
757329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            d.setState(getDrawableState());
758329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
759329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
760329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
7611cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // We want the duration of the page snap animation to be influenced by the distance that
7621cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // the screen has to travel, however, we don't want this duration to be effected in a
7631cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
7641cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // of travel has on the overall snap duration.
7651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    float distanceInfluenceForSnapDuration(float f) {
7661cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        f -= 0.5f; // center the values about 0.
7671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        f *= 0.3f * Math.PI / 2.0f;
7681cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        return (float) Math.sin(f);
7691cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
7701cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
771329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
772d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
773d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     *
774cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param x the number of pixels to scroll by on the X axis
775cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param y the number of pixels to scroll by on the Y axis
776d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
777d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void smoothScrollTo(int x, int y) {
7781cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        smoothScrollTo(x, y, 0);
7791cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
7801cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
7811cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    /**
7821cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
7831cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     *
7841cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param x the number of pixels to scroll by on the X axis
7851cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param y the number of pixels to scroll by on the Y axis
7861cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)
7871cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     */
7881cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    void smoothScrollTo(int x, int y, int velocity) {
789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (getChildCount() == 0) {
790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Nothing to do.
791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int sx = getScrollX();
795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int sy = getScrollY();
7963661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        int dx = x - sx;
7973661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        int dy = y - sy;
7983661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (dx == 0 && dy == 0) {
79971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio            completeScroll(false);
80031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            populate();
8013040c142491acd4a09e7d0add073be0067aec2d5Adam Powell            setScrollState(SCROLL_STATE_IDLE);
8023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            return;
8033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
8043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
8053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        setScrollingCacheEnabled(true);
80647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        setScrollState(SCROLL_STATE_SETTLING);
8071cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
808becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu        final int width = getClientWidth();
809035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final int halfWidth = width / 2;
810035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
811035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final float distance = halfWidth + halfWidth *
812035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                distanceInfluenceForSnapDuration(distanceRatio);
8131cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
814035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        int duration = 0;
8151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        velocity = Math.abs(velocity);
8161cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        if (velocity > 0) {
817035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
8181cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        } else {
819a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
821035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            duration = (int) ((pageDelta + 1) * 100);
8221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        }
8231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        duration = Math.min(duration, MAX_SETTLE_DURATION);
8241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
8251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        mScroller.startScroll(sx, sy, dx, dy, duration);
826b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell        ViewCompat.postInvalidateOnAnimation(this);
827d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
828d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    ItemInfo addNewItem(int position, int index) {
830d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ItemInfo ii = new ItemInfo();
831d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ii.position = position;
8325c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        ii.object = mAdapter.instantiateItem(this, position);
833a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ii.widthFactor = mAdapter.getPageWidth(position);
834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (index < 0 || index >= mItems.size()) {
835d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mItems.add(ii);
836d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mItems.add(index, ii);
838d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        return ii;
840d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
841d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
8423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    void dataSetChanged() {
8433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        // This method only gets called if our observer is attached, so mAdapter is non-null.
8443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
845199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell        final int adapterCount = mAdapter.getCount();
846199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell        mExpectedAdapterCount = adapterCount;
8471a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell        boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 &&
848199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                mItems.size() < adapterCount;
8491e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell        int newCurrItem = mCurItem;
8503661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
8519508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        boolean isUpdating = false;
8523661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        for (int i = 0; i < mItems.size(); i++) {
8533661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            final ItemInfo ii = mItems.get(i);
8543661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            final int newPos = mAdapter.getItemPosition(ii.object);
8553661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
8563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
8573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                continue;
8583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
8593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
8603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (newPos == PagerAdapter.POSITION_NONE) {
8613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mItems.remove(i);
8623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                i--;
8639508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
8649508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                if (!isUpdating) {
8659508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                    mAdapter.startUpdate(this);
8669508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                    isUpdating = true;
8679508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                }
8689508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
8693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mAdapter.destroyItem(this, ii.position, ii.object);
8703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                needPopulate = true;
8713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
8723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (mCurItem == ii.position) {
8733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    // Keep the current item in the valid range
874199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                    newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
8751a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell                    needPopulate = true;
8763661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
8773661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                continue;
8783661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
8793661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
8803661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (ii.position != newPos) {
8813661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (ii.position == mCurItem) {
8823661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    // Our current item changed position. Follow it.
8833661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    newCurrItem = newPos;
8843661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
8853661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
8863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                ii.position = newPos;
8873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                needPopulate = true;
8883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
8893661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
8903661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
8919508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        if (isUpdating) {
8929508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell            mAdapter.finishUpdate(this);
8939508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        }
8949508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
89566c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        Collections.sort(mItems, COMPARATOR);
89666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham
897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (needPopulate) {
898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Reset our known page widths; populate will recompute them.
899a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int childCount = getChildCount();
900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int i = 0; i < childCount; i++) {
901a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final View child = getChildAt(i);
902a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
903a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (!lp.isDecor) {
904a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    lp.widthFactor = 0.f;
905a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
906a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
907a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
908d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell            setCurrentItemInternal(newCurrItem, false, true);
9093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            requestLayout();
9103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
9113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
9123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
913d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void populate() {
914a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        populate(mCurItem);
915a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
916a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
917a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    void populate(int newCurrentItem) {
918a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ItemInfo oldCurInfo = null;
919860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu        int focusDirection = View.FOCUS_FORWARD;
920a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mCurItem != newCurrentItem) {
921860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu            focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
922a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            oldCurInfo = infoForPosition(mCurItem);
923a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            mCurItem = newCurrentItem;
924a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
925a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
926d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter == null) {
927f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            sortChildDrawingOrder();
928d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
929d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
930d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
931d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Bail now if we are waiting to populate.  This is to hold off
932d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // on creating views from the time the user releases their finger to
933d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // fling to a new position until we have finished the scroll to
934d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // that position, avoiding glitches from happening at that point.
935d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mPopulatePending) {
9363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
937f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            sortChildDrawingOrder();
938d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
939d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
940d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
941ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // Also, don't populate until we are attached to a window.  This is to
942ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // avoid trying to populate before we have restored our view hierarchy
943ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // state and conflicting with what is restored.
944ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        if (getWindowToken() == null) {
945ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            return;
946ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        }
947ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn
9485c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mAdapter.startUpdate(this);
949d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
95029a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int pageLimit = mOffscreenPageLimit;
95129a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int startPos = Math.max(0, mCurItem - pageLimit);
9524c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        final int N = mAdapter.getCount();
95329a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int endPos = Math.min(N-1, mCurItem + pageLimit);
954d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
955199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell        if (N != mExpectedAdapterCount) {
956199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell            String resName;
957199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell            try {
958199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                resName = getResources().getResourceName(getId());
959199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell            } catch (Resources.NotFoundException e) {
960199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                resName = Integer.toHexString(getId());
961199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell            }
962199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell            throw new IllegalStateException("The application's PagerAdapter changed the adapter's" +
963199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                    " contents without calling PagerAdapter#notifyDataSetChanged!" +
964199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                    " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N +
965199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                    " Pager id: " + resName +
966199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                    " Pager class: " + getClass() +
967199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell                    " Problematic adapter: " + mAdapter.getClass());
968199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell        }
969199a13cf79b43494ea381a91ee67f0da1f1d10deAdam Powell
970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Locate the currently focused item or add it if needed.
971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int curIndex = -1;
972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ItemInfo curItem = null;
973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(curIndex);
975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position >= mCurItem) {
976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (ii.position == mCurItem) curItem = ii;
977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                break;
978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
980d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (curItem == null && N > 0) {
982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            curItem = addNewItem(mCurItem, curIndex);
983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
984a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Fill 3x the available width or up to the number of offscreen
986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // pages requested to either side, whichever is larger.
987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // If we have no current item we have no work to do.
988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (curItem != null) {
989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float extraWidthLeft = 0.f;
990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int itemIndex = curIndex - 1;
991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
9924f4c3a3978997e552c44726fb2862e4461497384Adam Powell            final int clientWidth = getClientWidth();
9934f4c3a3978997e552c44726fb2862e4461497384Adam Powell            final float leftWidthNeeded = clientWidth <= 0 ? 0 :
9944f4c3a3978997e552c44726fb2862e4461497384Adam Powell                    2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth;
995a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int pos = mCurItem - 1; pos >= 0; pos--) {
99631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
997a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (ii == null) {
998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        break;
999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (pos == ii.position && !ii.scrolling) {
1001a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        mItems.remove(itemIndex);
1002a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        mAdapter.destroyItem(this, pos, ii.object);
100371d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                        if (DEBUG) {
100471d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                            Log.i(TAG, "populate() - destroyItem() with pos: " + pos +
100571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                                    " view: " + ((View) ii.object));
100671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                        }
1007a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex--;
1008a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        curIndex--;
1009a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
1010a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1011a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else if (ii != null && pos == ii.position) {
1012a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    extraWidthLeft += ii.widthFactor;
1013a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    itemIndex--;
1014a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
1015a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else {
1016a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = addNewItem(pos, itemIndex + 1);
1017a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    extraWidthLeft += ii.widthFactor;
1018a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    curIndex++;
1019a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
10204c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                }
1021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1022d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1023a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float extraWidthRight = curItem.widthFactor;
1024a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            itemIndex = curIndex + 1;
1025a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (extraWidthRight < 2.f) {
1026a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
10274f4c3a3978997e552c44726fb2862e4461497384Adam Powell                final float rightWidthNeeded = clientWidth <= 0 ? 0 :
10284f4c3a3978997e552c44726fb2862e4461497384Adam Powell                        (float) getPaddingRight() / (float) clientWidth + 2.f;
1029a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = mCurItem + 1; pos < N; pos++) {
1030becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu                    if (extraWidthRight >= rightWidthNeeded && pos > endPos) {
1031a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (ii == null) {
1032a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            break;
1033a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
1034a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (pos == ii.position && !ii.scrolling) {
1035a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            mItems.remove(itemIndex);
1036a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            mAdapter.destroyItem(this, pos, ii.object);
103771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                            if (DEBUG) {
103871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                                Log.i(TAG, "populate() - destroyItem() with pos: " + pos +
103971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                                        " view: " + ((View) ii.object));
104071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                            }
1041a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
1042a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
1043a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    } else if (ii != null && pos == ii.position) {
1044a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        extraWidthRight += ii.widthFactor;
1045a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
1046a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
1047a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    } else {
1048a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = addNewItem(pos, itemIndex);
1049a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
1050a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        extraWidthRight += ii.widthFactor;
1051a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
1052a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1053a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1054d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1055a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1056a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            calculatePageOffsets(curItem, curIndex, oldCurInfo);
1057d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1058d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
10594c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        if (DEBUG) {
10604c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            Log.i(TAG, "Current page list:");
10614c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            for (int i=0; i<mItems.size(); i++) {
10624c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);
1063d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1064d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1065d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
10662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
10672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
10685c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mAdapter.finishUpdate(this);
10692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
10707e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        // Check width measurement of current pages and drawing sort order.
10717e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        // Update LayoutParams as needed.
1072a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int childCount = getChildCount();
1073a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < childCount; i++) {
1074a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final View child = getChildAt(i);
1075a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
10767e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            lp.childIndex = i;
1077a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (!lp.isDecor && lp.widthFactor == 0.f) {
1078a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                // 0 means requery the adapter for this, it doesn't have a valid width.
1079a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final ItemInfo ii = infoForChild(child);
1080a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (ii != null) {
1081a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    lp.widthFactor = ii.widthFactor;
10827e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell                    lp.position = ii.position;
1083a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1084a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1085a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1086f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell        sortChildDrawingOrder();
1087a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
10882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (hasFocus()) {
10892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            View currentFocused = findFocus();
1090218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
10912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (ii == null || ii.position != mCurItem) {
10922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                for (int i=0; i<getChildCount(); i++) {
10932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    View child = getChildAt(i);
10942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    ii = infoForChild(child);
10952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (ii != null && ii.position == mCurItem) {
1096860155ee7a4c7968f3cbe1d8dbb0c8a35f9fec2dDake Gu                        if (child.requestFocus(focusDirection)) {
10972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                            break;
10982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        }
10992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
11002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
11012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
11022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
1103d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1105f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell    private void sortChildDrawingOrder() {
1106f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell        if (mDrawingOrder != DRAW_ORDER_DEFAULT) {
1107f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            if (mDrawingOrderedChildren == null) {
1108f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                mDrawingOrderedChildren = new ArrayList<View>();
1109f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            } else {
1110f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                mDrawingOrderedChildren.clear();
1111f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            }
1112f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            final int childCount = getChildCount();
1113f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            for (int i = 0; i < childCount; i++) {
1114f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                final View child = getChildAt(i);
1115f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell                mDrawingOrderedChildren.add(child);
1116f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            }
1117f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell            Collections.sort(mDrawingOrderedChildren, sPositionComparator);
1118f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell        }
1119f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell    }
1120f1452d17be15651c6047ec4eb7ff5892538e8265Adam Powell
1121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) {
1122a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int N = mAdapter.getCount();
1123becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu        final int width = getClientWidth();
1124a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
1125a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Fix up offsets for later layout.
1126a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (oldCurInfo != null) {
1127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int oldCurPosition = oldCurInfo.position;
1128a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Base offsets off of oldCurInfo.
1129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (oldCurPosition < curItem.position) {
1130a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                int itemIndex = 0;
1131a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii = null;
11326bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell                float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset;
1133a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = oldCurPosition + 1;
1134a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos <= curItem.position && itemIndex < mItems.size(); pos++) {
1135a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(itemIndex);
1136a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos > ii.position && itemIndex < mItems.size() - 1) {
1137a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
1138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = mItems.get(itemIndex);
1139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos < ii.position) {
1141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // We don't have an item populated for this,
1142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // ask the adapter for an offset.
1143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        offset += mAdapter.getPageWidth(pos) + marginOffset;
1144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos++;
1145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii.offset = offset;
1147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset += ii.widthFactor + marginOffset;
1148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            } else if (oldCurPosition > curItem.position) {
1150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                int itemIndex = mItems.size() - 1;
1151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii = null;
1152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                float offset = oldCurInfo.offset;
1153a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = oldCurPosition - 1;
1154a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos >= curItem.position && itemIndex >= 0; pos--) {
1155a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(itemIndex);
1156a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos < ii.position && itemIndex > 0) {
1157a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex--;
1158a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = mItems.get(itemIndex);
1159a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1160a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos > ii.position) {
1161a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // We don't have an item populated for this,
1162a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // ask the adapter for an offset.
1163a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        offset -= mAdapter.getPageWidth(pos) + marginOffset;
1164a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos--;
1165a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1166a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset -= ii.widthFactor + marginOffset;
1167a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii.offset = offset;
1168a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1169a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1170a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1171a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1172a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Base all offsets off of curItem.
1173a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int itemCount = mItems.size();
1174a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float offset = curItem.offset;
1175a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int pos = curItem.position - 1;
1176a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE;
117731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        mLastOffset = curItem.position == N - 1 ?
117831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE;
1179a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Previous pages
1180a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = curIndex - 1; i >= 0; i--, pos--) {
1181a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(i);
1182a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            while (pos > ii.position) {
1183a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                offset -= mAdapter.getPageWidth(pos--) + marginOffset;
1184a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1185a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset -= ii.widthFactor + marginOffset;
1186a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ii.offset = offset;
1187a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position == 0) mFirstOffset = offset;
1188a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1189a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        offset = curItem.offset + curItem.widthFactor + marginOffset;
1190a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        pos = curItem.position + 1;
1191a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Next pages
1192a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = curIndex + 1; i < itemCount; i++, pos++) {
1193a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(i);
1194a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            while (pos < ii.position) {
1195a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                offset += mAdapter.getPageWidth(pos++) + marginOffset;
1196a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
119731bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            if (ii.position == N - 1) {
119831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                mLastOffset = offset + ii.widthFactor - 1;
119931bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            }
1200a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ii.offset = offset;
1201a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset += ii.widthFactor + marginOffset;
1202a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1203a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1204a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mNeedCalculatePageOffsets = false;
1205a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
1206a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
12077dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn    /**
12087dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * This is the persistent state that is saved by ViewPager.  Only needed
12097dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * if you are creating a sublass of ViewPager that must save its own
12107dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * state, in which case it should implement a subclass of this which
12117dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * contains that state.
12127dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     */
1213d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public static class SavedState extends BaseSavedState {
1214d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int position;
1215ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        Parcelable adapterState;
12165c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        ClassLoader loader;
1217d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
12185c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        public SavedState(Parcelable superState) {
1219d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super(superState);
1220d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1221d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1222d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        @Override
1223d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        public void writeToParcel(Parcel out, int flags) {
1224d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.writeToParcel(out, flags);
1225d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            out.writeInt(position);
12265c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            out.writeParcelable(adapterState, flags);
1227d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1228d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1229d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        @Override
1230d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        public String toString() {
1231d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return "FragmentPager.SavedState{"
1232d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    + Integer.toHexString(System.identityHashCode(this))
1233d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    + " position=" + position + "}";
1234d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1235d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
12365c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        public static final Parcelable.Creator<SavedState> CREATOR
12375c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
12385c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    @Override
12395c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
12405c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        return new SavedState(in, loader);
12415c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    }
12425c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    @Override
12435c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    public SavedState[] newArray(int size) {
12445c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        return new SavedState[size];
12455c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    }
12465c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                });
12475c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
12485c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        SavedState(Parcel in, ClassLoader loader) {
1249d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super(in);
12505c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            if (loader == null) {
12515c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                loader = getClass().getClassLoader();
1252ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            }
12535c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            position = in.readInt();
12545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            adapterState = in.readParcelable(loader);
12555c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            this.loader = loader;
1256d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1257d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1258d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1259d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1260d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public Parcelable onSaveInstanceState() {
1261d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        Parcelable superState = super.onSaveInstanceState();
1262d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        SavedState ss = new SavedState(superState);
1263d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ss.position = mCurItem;
1264677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki        if (mAdapter != null) {
1265677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki            ss.adapterState = mAdapter.saveState();
1266677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki        }
1267d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return ss;
1268d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1269d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1270d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1271d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void onRestoreInstanceState(Parcelable state) {
1272d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (!(state instanceof SavedState)) {
1273d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.onRestoreInstanceState(state);
1274d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
1275d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1276d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1277d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        SavedState ss = (SavedState)state;
1278d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super.onRestoreInstanceState(ss.getSuperState());
1279d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1280d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter != null) {
12815c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mAdapter.restoreState(ss.adapterState, ss.loader);
1282d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setCurrentItemInternal(ss.position, false, true);
1283d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
1284d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mRestoredCurItem = ss.position;
1285ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            mRestoredAdapterState = ss.adapterState;
12865c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mRestoredClassLoader = ss.loader;
1287d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1288d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1289d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
12918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public void addView(View child, int index, ViewGroup.LayoutParams params) {
12921ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        if (!checkLayoutParams(params)) {
12931ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell            params = generateLayoutParams(params);
12941ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        }
12951ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        final LayoutParams lp = (LayoutParams) params;
12961ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        lp.isDecor |= child instanceof Decor;
1297d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mInLayout) {
12988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (lp != null && lp.isDecor) {
12998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                throw new IllegalStateException("Cannot add pager decor view during layout");
13008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
1301a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lp.needsMeasure = true;
1302d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            addViewInLayout(child, index, params);
1303d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
1304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.addView(child, index, params);
1305d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1307d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (USE_CACHE) {
1308d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (child.getVisibility() != GONE) {
1309d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                child.setDrawingCacheEnabled(mScrollingCacheEnabled);
1310d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            } else {
1311d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                child.setDrawingCacheEnabled(false);
1312d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1315d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
131637a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase    @Override
131737a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase    public void removeView(View view) {
131837a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase        if (mInLayout) {
131937a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase            removeViewInLayout(view);
132037a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase        } else {
132137a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase            super.removeView(view);
132237a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase        }
132337a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase    }
132437a7c5d234e23a4a3290bc75b064b355870e2622Chet Haase
1325d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    ItemInfo infoForChild(View child) {
1326d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i=0; i<mItems.size(); i++) {
1327d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            ItemInfo ii = mItems.get(i);
1328ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            if (mAdapter.isViewFromObject(child, ii.object)) {
1329d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return ii;
1330d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1331d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1332d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return null;
1333d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1334d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1335218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn    ItemInfo infoForAnyChild(View child) {
1336218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        ViewParent parent;
1337218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        while ((parent=child.getParent()) != this) {
1338218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            if (parent == null || !(parent instanceof View)) {
1339218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn                return null;
1340218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            }
1341218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            child = (View)parent;
1342218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        }
1343218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        return infoForChild(child);
1344218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn    }
1345218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn
1346a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    ItemInfo infoForPosition(int position) {
1347a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < mItems.size(); i++) {
1348a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(i);
1349a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position == position) {
1350a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                return ii;
1351a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1352a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1353a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        return null;
1354a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
1355a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1356d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1357ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    protected void onAttachedToWindow() {
1358ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        super.onAttachedToWindow();
135997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mFirstLayout = true;
1360ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    }
1361ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn
1362ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    @Override
1363d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1364fdd9223ac2d8fc0c7a74a076c1cd4defc7acf499Adam Powell        // For simple implementation, our internal size is always 0.
1365d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // We depend on the container to specify the layout size of
1366d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // our view.  We can't really know what it is since we will be
1367d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // adding and removing different arbitrary views and do not
1368d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // want the layout to change as this happens.
1369d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
1370d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                getDefaultSize(0, heightMeasureSpec));
1371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
13728f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        final int measuredWidth = getMeasuredWidth();
13738f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        final int maxGutterSize = measuredWidth / 10;
13748f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);
13758f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell
1376d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Children are just made to fill our space.
13778f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
13788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
13798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
13808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        /*
13818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * Make sure all children have been properly measured. Decor views first.
13828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * Right now we cheat and make this less complicated by assuming decor
13838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * views won't intersect. We will pin to edges based on gravity.
13848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         */
1385862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell        int size = getChildCount();
13868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        for (int i = 0; i < size; ++i) {
13878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final View child = getChildAt(i);
13888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (child.getVisibility() != GONE) {
13898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
13908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp != null && lp.isDecor) {
13918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
13928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
13938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    int widthMode = MeasureSpec.AT_MOST;
13948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    int heightMode = MeasureSpec.AT_MOST;
13958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
13968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
13978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
13988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (consumeVertical) {
13998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        widthMode = MeasureSpec.EXACTLY;
14008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    } else if (consumeHorizontal) {
14018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        heightMode = MeasureSpec.EXACTLY;
14028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
14038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
1404a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int widthSize = childWidthSize;
1405a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int heightSize = childHeightSize;
1406a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.width != LayoutParams.WRAP_CONTENT) {
1407a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        widthMode = MeasureSpec.EXACTLY;
1408a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (lp.width != LayoutParams.FILL_PARENT) {
1409a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            widthSize = lp.width;
1410a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
1411a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1412a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.height != LayoutParams.WRAP_CONTENT) {
1413a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        heightMode = MeasureSpec.EXACTLY;
1414a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (lp.height != LayoutParams.FILL_PARENT) {
1415a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            heightSize = lp.height;
1416a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
1417a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1418a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
1419a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
14208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    child.measure(widthSpec, heightSpec);
14218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (consumeVertical) {
14238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childHeightSize -= child.getMeasuredHeight();
14248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    } else if (consumeHorizontal) {
14258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childWidthSize -= child.getMeasuredWidth();
14268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
14278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
14288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
14298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
14308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
14328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
1433d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Make sure we have created all fragments that we need to have shown.
1435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = true;
1436d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        populate();
1437d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = false;
1438d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
14398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        // Page views next.
1440862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell        size = getChildCount();
1441d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i = 0; i < size; ++i) {
1442d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            final View child = getChildAt(i);
1443d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (child.getVisibility() != GONE) {
1444d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child
14458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        + ": " + mChildWidthMeasureSpec);
14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
14488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp == null || !lp.isDecor) {
1449a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int widthSpec = MeasureSpec.makeMeasureSpec(
1450a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
1451a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    child.measure(widthSpec, mChildHeightMeasureSpec);
14528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
1453d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1454d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1455d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1456d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1457d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1458d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1459d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super.onSizeChanged(w, h, oldw, oldh);
1460d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1461d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Make sure scroll position is set correctly.
1462053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell        if (w != oldw) {
1463329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);
1464329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
1465329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
1466329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
1467329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) {
146891eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell        if (oldWidth > 0 && !mItems.isEmpty()) {
1469becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu            final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin;
1470becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu            final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight()
1471becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu                                           + oldMargin;
14728d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final int xpos = getScrollX();
14735f6568e7e269783e2668527461878cadfbe65215Adam Powell            final float pageOffset = (float) xpos / oldWidthWithMargin;
14745f6568e7e269783e2668527461878cadfbe65215Adam Powell            final int newOffsetPixels = (int) (pageOffset * widthWithMargin);
1475a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
14765f6568e7e269783e2668527461878cadfbe65215Adam Powell            scrollTo(newOffsetPixels, getScrollY());
1477329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            if (!mScroller.isFinished()) {
1478329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell                // We now return to your regularly scheduled scroll, already in progress.
1479329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell                final int newDuration = mScroller.getDuration() - mScroller.timePassed();
1480a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo targetInfo = infoForPosition(mCurItem);
14815f6568e7e269783e2668527461878cadfbe65215Adam Powell                mScroller.startScroll(newOffsetPixels, 0,
14828d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                        (int) (targetInfo.offset * width), 0, newDuration);
1483329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            }
1484329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        } else {
1485a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = infoForPosition(mCurItem);
14868d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0;
1487becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu            final int scrollPos = (int) (scrollOffset *
1488becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu                                         (width - getPaddingLeft() - getPaddingRight()));
1489329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            if (scrollPos != getScrollX()) {
149071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                completeScroll(false);
1491053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell                scrollTo(scrollPos, getScrollY());
14929bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell            }
1493d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1494d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1495d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1496d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1497d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onLayout(boolean changed, int l, int t, int r, int b) {
1498d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int count = getChildCount();
14998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int width = r - l;
15008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int height = b - t;
15018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingLeft = getPaddingLeft();
15028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingTop = getPaddingTop();
15038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingRight = getPaddingRight();
15048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingBottom = getPaddingBottom();
15058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int scrollX = getScrollX();
15068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
15078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int decorCount = 0;
1508d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1509a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // First pass - decor views. We need to do this in two passes so that
1510a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // we have the proper offsets for non-decor views later.
1511d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i = 0; i < count; i++) {
15128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final View child = getChildAt(i);
15138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (child.getVisibility() != GONE) {
15148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
15158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childLeft = 0;
15168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childTop = 0;
15178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp.isDecor) {
15188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
15198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
15208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    switch (hgrav) {
15218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        default:
15228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = paddingLeft;
15238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
15248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.LEFT:
15258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = paddingLeft;
15268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingLeft += child.getMeasuredWidth();
15278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
15288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.CENTER_HORIZONTAL:
15298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
15308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                    paddingLeft);
15318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
15328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.RIGHT:
15338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = width - paddingRight - child.getMeasuredWidth();
15348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingRight += child.getMeasuredWidth();
15358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
15368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
15378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    switch (vgrav) {
15388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        default:
15398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = paddingTop;
15408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
15418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.TOP:
15428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = paddingTop;
15438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingTop += child.getMeasuredHeight();
15448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
15458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.CENTER_VERTICAL:
15468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = Math.max((height - child.getMeasuredHeight()) / 2,
15478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                    paddingTop);
15488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
15498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.BOTTOM:
15508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = height - paddingBottom - child.getMeasuredHeight();
15518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingBottom += child.getMeasuredHeight();
15528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
15538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
15548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    childLeft += scrollX;
1555abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                    child.layout(childLeft, childTop,
1556abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childLeft + child.getMeasuredWidth(),
1557abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childTop + child.getMeasuredHeight());
1558a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    decorCount++;
1559a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1560a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1561a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1562a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1563becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu        final int childWidth = width - paddingLeft - paddingRight;
1564a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Page views. Do this once we have the right padding offsets from above.
1565a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < count; i++) {
1566a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final View child = getChildAt(i);
1567a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (child.getVisibility() != GONE) {
1568a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1569a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii;
1570a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (!lp.isDecor && (ii = infoForChild(child)) != null) {
1571becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu                    int loff = (int) (childWidth * ii.offset);
1572a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int childLeft = paddingLeft + loff;
1573a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int childTop = paddingTop;
1574a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.needsMeasure) {
1575a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // This was added during layout and needs measurement.
1576a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // Do it now that we know what we're working with.
1577a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        lp.needsMeasure = false;
1578a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        final int widthSpec = MeasureSpec.makeMeasureSpec(
1579becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu                                (int) (childWidth * lp.widthFactor),
1580a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                MeasureSpec.EXACTLY);
1581a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        final int heightSpec = MeasureSpec.makeMeasureSpec(
1582a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                (int) (height - paddingTop - paddingBottom),
1583a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                MeasureSpec.EXACTLY);
1584a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        child.measure(widthSpec, heightSpec);
1585a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
15868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object
15878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth()
15888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            + "x" + child.getMeasuredHeight());
1589abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                    child.layout(childLeft, childTop,
1590abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childLeft + child.getMeasuredWidth(),
1591abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childTop + child.getMeasuredHeight());
15928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
1593d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1594d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
15958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mTopPageBounds = paddingTop;
15968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mBottomPageBounds = height - paddingBottom;
15978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mDecorChildCount = decorCount;
159844fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell
159944fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell        if (mFirstLayout) {
160044fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell            scrollToItem(mCurItem, false, 0, false);
160144fc13985aed09d1fda3fdf2fd900ec13720a5dfAdam Powell        }
160297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mFirstLayout = false;
1603d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1604d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1605d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1606d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void computeScroll() {
1607a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
1608a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int oldX = getScrollX();
1609a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int oldY = getScrollY();
1610a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int x = mScroller.getCurrX();
1611a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int y = mScroller.getCurrY();
16123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
1613a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (oldX != x || oldY != y) {
1614a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                scrollTo(x, y);
16154783095cc69fa85e484132337526c94d42d41c43Adam Powell                if (!pageScrolled(x)) {
16164783095cc69fa85e484132337526c94d42d41c43Adam Powell                    mScroller.abortAnimation();
16174783095cc69fa85e484132337526c94d42d41c43Adam Powell                    scrollTo(0, y);
16184783095cc69fa85e484132337526c94d42d41c43Adam Powell                }
1619d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1620a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1621a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Keep on drawing until the animation has finished.
1622b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
1623a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            return;
1624d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
16254c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn
16264c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        // Done with scroll, clean up state.
162771d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio        completeScroll(true);
1628d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1629d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
16304783095cc69fa85e484132337526c94d42d41c43Adam Powell    private boolean pageScrolled(int xpos) {
16314783095cc69fa85e484132337526c94d42d41c43Adam Powell        if (mItems.size() == 0) {
16324783095cc69fa85e484132337526c94d42d41c43Adam Powell            mCalledSuper = false;
16334783095cc69fa85e484132337526c94d42d41c43Adam Powell            onPageScrolled(0, 0, 0);
16344783095cc69fa85e484132337526c94d42d41c43Adam Powell            if (!mCalledSuper) {
16354783095cc69fa85e484132337526c94d42d41c43Adam Powell                throw new IllegalStateException(
16364783095cc69fa85e484132337526c94d42d41c43Adam Powell                        "onPageScrolled did not call superclass implementation");
16374783095cc69fa85e484132337526c94d42d41c43Adam Powell            }
16384783095cc69fa85e484132337526c94d42d41c43Adam Powell            return false;
16394783095cc69fa85e484132337526c94d42d41c43Adam Powell        }
1640a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo ii = infoForCurrentScrollPosition();
1641becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu        final int width = getClientWidth();
1642a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int widthWithMargin = width + mPageMargin;
1643a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = (float) mPageMargin / width;
1644a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int currentPage = ii.position;
1645a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float pageOffset = (((float) xpos / width) - ii.offset) /
1646a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                (ii.widthFactor + marginOffset);
1647a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int offsetPixels = (int) (pageOffset * widthWithMargin);
16488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
16498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCalledSuper = false;
1650a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        onPageScrolled(currentPage, pageOffset, offsetPixels);
16518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (!mCalledSuper) {
16528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            throw new IllegalStateException(
16538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    "onPageScrolled did not call superclass implementation");
16548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
16554783095cc69fa85e484132337526c94d42d41c43Adam Powell        return true;
16568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
16578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
16588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
16598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * This method will be invoked when the current page is scrolled, either as part
16608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
16618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * If you override this method you must call through to the superclass implementation
16628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled
16638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * returns.
16648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
16658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param position Position index of the first page currently being displayed.
16668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *                 Page position+1 will be visible if positionOffset is nonzero.
16678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param offset Value from [0, 1) indicating the offset from the page at position.
16688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param offsetPixels Value in pixels indicating the offset from position.
16698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
16708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected void onPageScrolled(int position, float offset, int offsetPixels) {
16718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        // Offset any decor views if needed - keep them on-screen at all times.
16728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mDecorChildCount > 0) {
16738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int scrollX = getScrollX();
16748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            int paddingLeft = getPaddingLeft();
16758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            int paddingRight = getPaddingRight();
16768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int width = getWidth();
16778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int childCount = getChildCount();
16788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            for (int i = 0; i < childCount; i++) {
16798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final View child = getChildAt(i);
16808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
16818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (!lp.isDecor) continue;
16828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
16838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
16848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childLeft = 0;
16858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                switch (hgrav) {
16868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    default:
16878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = paddingLeft;
16888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
16898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.LEFT:
16908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = paddingLeft;
16918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        paddingLeft += child.getWidth();
16928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
16938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.CENTER_HORIZONTAL:
16948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
16958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                paddingLeft);
16968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
16978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.RIGHT:
16988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = width - paddingRight - child.getMeasuredWidth();
16998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        paddingRight += child.getMeasuredWidth();
17008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
17018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
17028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                childLeft += scrollX;
17038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
17048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final int childOffset = childLeft - child.getLeft();
17058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (childOffset != 0) {
17068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    child.offsetLeftAndRight(childOffset);
17078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
17088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
17098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
17108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
17118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mOnPageChangeListener != null) {
17128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);
17138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
17148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mInternalPageChangeListener != null) {
17158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);
17168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
17178a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell
17188a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        if (mPageTransformer != null) {
17198a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            final int scrollX = getScrollX();
17208a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            final int childCount = getChildCount();
17218a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            for (int i = 0; i < childCount; i++) {
17228a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell                final View child = getChildAt(i);
17237e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
17247e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell
17257e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell                if (lp.isDecor) continue;
17267e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell
1727becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu                final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
17288a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell                mPageTransformer.transformPage(child, transformPos);
17298a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            }
17308a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        }
17318a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell
17328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCalledSuper = true;
17338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
17348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
173571d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio    private void completeScroll(boolean postEvents) {
17368d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell        boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;
1737cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham        if (needPopulate) {
17384c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // Done with scroll, no longer want to cache view drawing.
17394c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            setScrollingCacheEnabled(false);
1740d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mScroller.abortAnimation();
1741d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int oldX = getScrollX();
1742d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int oldY = getScrollY();
1743d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int x = mScroller.getCurrX();
1744d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int y = mScroller.getCurrY();
1745d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (oldX != x || oldY != y) {
1746d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                scrollTo(x, y);
1747d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
17484c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
17493661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        mPopulatePending = false;
17504c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        for (int i=0; i<mItems.size(); i++) {
17514c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            ItemInfo ii = mItems.get(i);
17524c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            if (ii.scrolling) {
17534c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                needPopulate = true;
17544c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                ii.scrolling = false;
17554c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            }
17564c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
17574c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        if (needPopulate) {
175871d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio            if (postEvents) {
175971d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                ViewCompat.postOnAnimation(this, mEndScrollRunnable);
176071d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio            } else {
176171d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                mEndScrollRunnable.run();
176271d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio            }
1763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1764d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1765d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
17668f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private boolean isGutterDrag(float x, float dx) {
17678f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0);
17688f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    }
17698f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell
17708a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    private void enableLayers(boolean enable) {
17718a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        final int childCount = getChildCount();
17728a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        for (int i = 0; i < childCount; i++) {
17738a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            final int layerType = enable ?
17748a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell                    ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE;
17758a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell            ViewCompat.setLayerType(getChildAt(i), layerType, null);
17768a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell        }
17778a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell    }
17788a0c51a3d438802df28612e02fdf0cc8fab06ddbAdam Powell
1779d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1780d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public boolean onInterceptTouchEvent(MotionEvent ev) {
1781d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        /*
1782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * This method JUST determines whether we want to intercept the motion.
1783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * If we return true, onMotionEvent will be called and we do the actual
1784d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * scrolling there.
1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         */
1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
1788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Always take care of the touch gesture being complete.
1790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
1791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Release the drag.
1792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (DEBUG) Log.v(TAG, "Intercept done!");
1793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mIsBeingDragged = false;
1794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mIsUnableToDrag = false;
1795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mActivePointerId = INVALID_POINTER;
17963ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            if (mVelocityTracker != null) {
17973ce9274ccb8034c1787415c77307bbda36071bddAdam Powell                mVelocityTracker.recycle();
17983ce9274ccb8034c1787415c77307bbda36071bddAdam Powell                mVelocityTracker = null;
17993ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            }
1800d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return false;
1801d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1803d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Nothing more to do here if we have decided whether or not we
1804d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // are dragging.
1805d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (action != MotionEvent.ACTION_DOWN) {
1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mIsBeingDragged) {
1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Intercept returning true!");
1808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return true;
1809d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1810d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mIsUnableToDrag) {
1811d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Intercept returning false!");
1812d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return false;
1813d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1814d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1815d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1816d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        switch (action) {
1817d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_MOVE: {
1818d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1819d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
1820d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * whether the user has moved far enough from his original down touch.
1821d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 */
1822d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1823d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1824d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                * Locally do absolute value. mLastMotionY is set to the y value
1825d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                * of the down event.
1826d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                */
1827d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int activePointerId = mActivePointerId;
1828d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (activePointerId == INVALID_POINTER) {
1829d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    // If we don't have a valid id, the touch down wasn't on content.
1830d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    break;
1831d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1832d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1833d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
1834d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float x = MotionEventCompat.getX(ev, pointerIndex);
183547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                final float dx = x - mLastMotionX;
183647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                final float xDiff = Math.abs(dx);
1837d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float y = MotionEventCompat.getY(ev, pointerIndex);
183816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                final float yDiff = Math.abs(y - mInitialMotionY);
1839d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
1840bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
18418f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell                if (dx != 0 && !isGutterDrag(mLastMotionX, dx) &&
18428f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell                        canScroll(this, false, (int) dx, (int) x, (int) y)) {
1843bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    // Nested view has scrollable area under this point. Let it be handled there.
184416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                    mLastMotionX = x;
1845bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    mLastMotionY = y;
1846b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                    mIsUnableToDrag = true;
1847bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    return false;
1848bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                }
184916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
1850d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    if (DEBUG) Log.v(TAG, "Starting drag!");
1851d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mIsBeingDragged = true;
18520f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette                    requestParentDisallowInterceptTouchEvent(true);
185347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    setScrollState(SCROLL_STATE_DRAGGING);
18548d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                    mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop :
18558d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                            mInitialMotionX - mTouchSlop;
185616991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                    mLastMotionY = y;
1857d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    setScrollingCacheEnabled(true);
185816991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                } else if (yDiff > mTouchSlop) {
185916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                    // The finger has moved enough in the vertical
186016991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                    // direction to be counted as a drag...  abort
186116991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                    // any attempt to drag horizontally, to work correctly
186216991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                    // with children that have scrolling containers.
186316991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                    if (DEBUG) Log.v(TAG, "Starting unable to drag!");
186416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                    mIsUnableToDrag = true;
1865d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
18666e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                if (mIsBeingDragged) {
18676e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                    // Scroll to follow the motion event
18686e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                    if (performDrag(x)) {
18696e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                        ViewCompat.postInvalidateOnAnimation(this);
18706e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                    }
18716e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                }
1872d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1873d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1874d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1875d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_DOWN: {
1876d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1877d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * Remember location of down touch.
1878d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * ACTION_DOWN always refers to pointer index 0.
1879d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 */
1880d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = mInitialMotionX = ev.getX();
188116991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                mLastMotionY = mInitialMotionY = ev.getY();
1882d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
1883b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                mIsUnableToDrag = false;
1884d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
18858d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                mScroller.computeScrollOffset();
1886b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                if (mScrollState == SCROLL_STATE_SETTLING &&
1887b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                        Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
188847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    // Let the user 'catch' the pager as it animates.
18898d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                    mScroller.abortAnimation();
18908d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                    mPopulatePending = false;
18918d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                    populate();
189247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    mIsBeingDragged = true;
18930f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette                    requestParentDisallowInterceptTouchEvent(true);
189447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    setScrollState(SCROLL_STATE_DRAGGING);
189547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                } else {
189671d54737b6d60ec99799aabdf9b48d2da26d8ccbFabrice Di Meglio                    completeScroll(false);
189747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    mIsBeingDragged = false;
189847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                }
1899d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1900d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
1901d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        + " mIsBeingDragged=" + mIsBeingDragged
1902d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        + "mIsUnableToDrag=" + mIsUnableToDrag);
1903d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1904d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1905d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1906d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_UP:
1907d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                onSecondaryPointerUp(ev);
1908d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1909d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1910d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
19118d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell        if (mVelocityTracker == null) {
19128d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            mVelocityTracker = VelocityTracker.obtain();
19133ce9274ccb8034c1787415c77307bbda36071bddAdam Powell        }
19148d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell        mVelocityTracker.addMovement(ev);
19153ce9274ccb8034c1787415c77307bbda36071bddAdam Powell
1916d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        /*
19173ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         * The only time we want to intercept motion events is if we are in the
19183ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         * drag mode.
19193ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         */
1920d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return mIsBeingDragged;
1921d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1922d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1923d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1924d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public boolean onTouchEvent(MotionEvent ev) {
192569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mFakeDragging) {
192669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // A fake drag is in progress already, ignore this real one
192769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // but still eat the touch events.
192869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // (It is likely that the user is multi-touching the screen.)
192969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            return true;
193069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
1931d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1932d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
1933d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Don't handle edge touches immediately -- they may actually belong to one of our
1934d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // descendants.
1935d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return false;
1936d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1937d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
19383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (mAdapter == null || mAdapter.getCount() == 0) {
19393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // Nothing to present or scroll; nothing to touch.
19403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            return false;
19413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
19423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
1943d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mVelocityTracker == null) {
1944d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker = VelocityTracker.obtain();
1945d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1946d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mVelocityTracker.addMovement(ev);
1947d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1948d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int action = ev.getAction();
1949560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        boolean needsInvalidate = false;
1950d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1951d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        switch (action & MotionEventCompat.ACTION_MASK) {
1952d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_DOWN: {
19538d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                mScroller.abortAnimation();
19548d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                mPopulatePending = false;
19558d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                populate();
1956d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1957d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                // Remember where the motion event started
1958d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = mInitialMotionX = ev.getX();
195916991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                mLastMotionY = mInitialMotionY = ev.getY();
1960d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
1961d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1962d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1963d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_MOVE:
19643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (!mIsBeingDragged) {
19653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
19663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final float x = MotionEventCompat.getX(ev, pointerIndex);
196747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    final float xDiff = Math.abs(x - mLastMotionX);
19683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final float y = MotionEventCompat.getY(ev, pointerIndex);
196947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    final float yDiff = Math.abs(y - mLastMotionY);
19703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
19713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    if (xDiff > mTouchSlop && xDiff > yDiff) {
19723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        if (DEBUG) Log.v(TAG, "Starting drag!");
19733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        mIsBeingDragged = true;
19740f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette                        requestParentDisallowInterceptTouchEvent(true);
19758d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                        mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
19768d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                                mInitialMotionX - mTouchSlop;
197716991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell                        mLastMotionY = y;
197847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                        setScrollState(SCROLL_STATE_DRAGGING);
19793661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        setScrollingCacheEnabled(true);
198023f32662b0e412510094d59c478f1d5370a15244Chris Banes
198123f32662b0e412510094d59c478f1d5370a15244Chris Banes                        // Disallow Parent Intercept, just in case
198223f32662b0e412510094d59c478f1d5370a15244Chris Banes                        ViewParent parent = getParent();
198323f32662b0e412510094d59c478f1d5370a15244Chris Banes                        if (parent != null) {
198423f32662b0e412510094d59c478f1d5370a15244Chris Banes                            parent.requestDisallowInterceptTouchEvent(true);
198523f32662b0e412510094d59c478f1d5370a15244Chris Banes                        }
19863661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    }
19873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
198831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                // Not else! Note that mIsBeingDragged can be set above.
1989d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
1990d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    // Scroll to follow the motion event
1991d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final int activePointerIndex = MotionEventCompat.findPointerIndex(
1992d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                            ev, mActivePointerId);
1993d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final float x = MotionEventCompat.getX(ev, activePointerIndex);
19946e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                    needsInvalidate |= performDrag(x);
1995d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1996d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1997d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_UP:
1998d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
1999d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final VelocityTracker velocityTracker = mVelocityTracker;
2000d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
20011cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
2002d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                            velocityTracker, mActivePointerId);
2003d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mPopulatePending = true;
2004becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu                    final int width = getClientWidth();
20051cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    final int scrollX = getScrollX();
2006a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final ItemInfo ii = infoForCurrentScrollPosition();
2007a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int currentPage = ii.position;
2008a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
2009035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final int activePointerIndex =
2010035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                            MotionEventCompat.findPointerIndex(ev, mActivePointerId);
2011035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final float x = MotionEventCompat.getX(ev, activePointerIndex);
2012035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final int totalDelta = (int) (x - mInitialMotionX);
2013035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
2014035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                            totalDelta);
20151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    setCurrentItemInternal(nextPage, true, true, initialVelocity);
2016d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2017d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mActivePointerId = INVALID_POINTER;
2018d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    endDrag();
2019560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
2020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
2021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
2022d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_CANCEL:
2023d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
2024a862399a9f738aa7e14012bc30491627f9dc6befPhilip Milne                    scrollToItem(mCurItem, true, 0, false);
2025d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mActivePointerId = INVALID_POINTER;
2026d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    endDrag();
2027560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
2028d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
2029d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
2030d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_DOWN: {
2031d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int index = MotionEventCompat.getActionIndex(ev);
2032d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float x = MotionEventCompat.getX(ev, index);
2033d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = x;
2034d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, index);
2035d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
2036d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
2037d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_UP:
2038d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                onSecondaryPointerUp(ev);
2039d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = MotionEventCompat.getX(ev,
2040d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        MotionEventCompat.findPointerIndex(ev, mActivePointerId));
2041d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
2042d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2043560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (needsInvalidate) {
2044b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
2045560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
2046d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return true;
2047d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
2048d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
20490f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette    private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
20500f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette        final ViewParent parent = getParent();
20510f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette        if (parent != null) {
20520f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette            parent.requestDisallowInterceptTouchEvent(disallowIntercept);
20530f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette        }
20540f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette    }
20550f86ecff5c3a1de3b53e9aede5048203cfa64551Alan Viverette
20566e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell    private boolean performDrag(float x) {
20576e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        boolean needsInvalidate = false;
20586e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
20596e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        final float deltaX = mLastMotionX - x;
20606e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        mLastMotionX = x;
20616e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
20626e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        float oldScrollX = getScrollX();
20636e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        float scrollX = oldScrollX + deltaX;
2064becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu        final int width = getClientWidth();
20656e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
20666e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        float leftBound = width * mFirstOffset;
20676e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        float rightBound = width * mLastOffset;
20686e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        boolean leftAbsolute = true;
20696e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        boolean rightAbsolute = true;
20706e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
20716e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        final ItemInfo firstItem = mItems.get(0);
20726e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
20736e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        if (firstItem.position != 0) {
20746e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            leftAbsolute = false;
20756e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            leftBound = firstItem.offset * width;
20766e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        }
20776e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        if (lastItem.position != mAdapter.getCount() - 1) {
20786e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            rightAbsolute = false;
20796e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            rightBound = lastItem.offset * width;
20806e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        }
20816e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
20826e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        if (scrollX < leftBound) {
20836e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            if (leftAbsolute) {
20846e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                float over = leftBound - scrollX;
20856e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width);
20866e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            }
20876e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            scrollX = leftBound;
20886e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        } else if (scrollX > rightBound) {
20896e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            if (rightAbsolute) {
20906e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                float over = scrollX - rightBound;
20916e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                needsInvalidate = mRightEdge.onPull(Math.abs(over) / width);
20926e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            }
20936e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            scrollX = rightBound;
20946e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        }
20956e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        // Don't lose the rounded component
20966e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        mLastMotionX += scrollX - (int) scrollX;
20976e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        scrollTo((int) scrollX, getScrollY());
20986e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        pageScrolled((int) scrollX);
20996e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
21006e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        return needsInvalidate;
21016e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell    }
21026e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
2103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    /**
2104a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * @return Info about the page at the current scroll position.
2105a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     *         This can be synthetic for a missing middle page; the 'object' field can be null.
2106a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     */
2107a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private ItemInfo infoForCurrentScrollPosition() {
2108becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu        final int width = getClientWidth();
2109a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0;
2110a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
2111a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int lastPos = -1;
2112a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float lastOffset = 0.f;
2113a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float lastWidth = 0.f;
2114a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        boolean first = true;
2115a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2116ad079a869adf67a87a2721342de27970a3ba1844Adam Powell        ItemInfo lastItem = null;
2117a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < mItems.size(); i++) {
2118a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(i);
2119a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float offset;
2120a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (!first && ii.position != lastPos + 1) {
2121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                // Create a synthetic item for a missing page.
2122a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii = mTempItem;
2123a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.offset = lastOffset + lastWidth + marginOffset;
2124a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.position = lastPos + 1;
2125a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.widthFactor = mAdapter.getPageWidth(ii.position);
2126a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                i--;
2127a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
2128a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset = ii.offset;
2129a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
21308d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final float leftBound = offset;
21318d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final float rightBound = offset + ii.widthFactor + marginOffset;
2132ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            if (first || scrollOffset >= leftBound) {
2133ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                if (scrollOffset < rightBound || i == mItems.size() - 1) {
2134ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                    return ii;
2135ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                }
2136ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            } else {
2137ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                return lastItem;
2138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
2139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            first = false;
2140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastPos = ii.position;
2141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastOffset = offset;
2142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastWidth = ii.widthFactor;
2143ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            lastItem = ii;
2144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
2145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2146ad079a869adf67a87a2721342de27970a3ba1844Adam Powell        return lastItem;
2147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
2148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2149035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
2150035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        int targetPage;
2151035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
2152035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            targetPage = velocity > 0 ? currentPage : currentPage + 1;
2153035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        } else {
215416991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell            final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
215516991ca86a49023bf6eb47b4e215bb1f2209de6dAdam Powell            targetPage = (int) (currentPage + pageOffset + truncator);
2156035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        }
2157035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell
2158a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mItems.size() > 0) {
2159a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo firstItem = mItems.get(0);
2160a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo lastItem = mItems.get(mItems.size() - 1);
2161a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2162a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Only let the user target pages we have items for
2163a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
2164a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
2165a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2166035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        return targetPage;
2167035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    }
2168035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell
2169560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    @Override
2170560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    public void draw(Canvas canvas) {
2171560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        super.draw(canvas);
2172560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        boolean needsInvalidate = false;
2173560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
2174560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        final int overScrollMode = ViewCompat.getOverScrollMode(this);
2175560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
2176560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS &&
2177560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                        mAdapter != null && mAdapter.getCount() > 1)) {
2178560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            if (!mLeftEdge.isFinished()) {
2179560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int restoreCount = canvas.save();
2180560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
2181a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final int width = getWidth();
2182560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
2183560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.rotate(270);
2184a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                canvas.translate(-height + getPaddingTop(), mFirstOffset * width);
2185a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                mLeftEdge.setSize(height, width);
2186560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                needsInvalidate |= mLeftEdge.draw(canvas);
2187560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.restoreToCount(restoreCount);
2188560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            }
2189560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            if (!mRightEdge.isFinished()) {
2190560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int restoreCount = canvas.save();
2191560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int width = getWidth();
2192560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
2193560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
2194560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.rotate(90);
2195a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width);
2196560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                mRightEdge.setSize(height, width);
2197560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                needsInvalidate |= mRightEdge.draw(canvas);
2198560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.restoreToCount(restoreCount);
2199560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            }
2200560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        } else {
2201560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            mLeftEdge.finish();
2202560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            mRightEdge.finish();
2203560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
2204560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
2205560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (needsInvalidate) {
2206560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            // Keep animating
2207b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
2208560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
2209560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    }
2210560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
2211329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
2212329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected void onDraw(Canvas canvas) {
2213329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        super.onDraw(canvas);
2214329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
2215a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Draw the margin drawable between pages if needed.
2216a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) {
2217329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            final int scrollX = getScrollX();
2218329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            final int width = getWidth();
2219a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2220a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float marginOffset = (float) mPageMargin / width;
2221a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int itemIndex = 0;
2222a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(0);
2223a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float offset = ii.offset;
2224a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int itemCount = mItems.size();
2225a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int firstPos = ii.position;
2226a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int lastPos = mItems.get(itemCount - 1).position;
2227a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int pos = firstPos; pos < lastPos; pos++) {
2228a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                while (pos > ii.position && itemIndex < itemCount) {
2229a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(++itemIndex);
2230a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
2231a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
223223b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                float drawAt;
2233a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (pos == ii.position) {
223423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                    drawAt = (ii.offset + ii.widthFactor) * width;
2235a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset = ii.offset + ii.widthFactor + marginOffset;
2236a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else {
2237a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    float widthFactor = mAdapter.getPageWidth(pos);
223823b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                    drawAt = (offset + widthFactor) * width;
2239a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset += widthFactor + marginOffset;
2240a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
2241a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2242a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (drawAt + mPageMargin > scrollX) {
2243a56d6faa9df608aaa2907864669800abb68acec7Adam Powell                    mMarginDrawable.setBounds((int) drawAt, mTopPageBounds,
224423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                            (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds);
2245a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    mMarginDrawable.draw(canvas);
2246a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
2247a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2248a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (drawAt > scrollX + width) {
2249a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    break; // No more visible, no sense in continuing
2250a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
2251329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            }
2252329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
2253329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
2254329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
225569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
225669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Start a fake drag of the pager.
225769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
225869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager
225969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * with the touch scrolling of another view, while still letting the ViewPager
226069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.)
226169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call
226269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * {@link #endFakeDrag()} to complete the fake drag and fling as necessary.
226369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
226469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag
226569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * is already in progress, this method will return false.
226669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
226769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @return true if the fake drag began successfully, false if it could not be started.
226869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
226969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
227069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
227169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
227269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public boolean beginFakeDrag() {
227369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mIsBeingDragged) {
227469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            return false;
227569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
227669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragging = true;
227769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        setScrollState(SCROLL_STATE_DRAGGING);
227869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mInitialMotionX = mLastMotionX = 0;
227969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mVelocityTracker == null) {
228069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            mVelocityTracker = VelocityTracker.obtain();
228169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        } else {
228269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            mVelocityTracker.clear();
228369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
228469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final long time = SystemClock.uptimeMillis();
228569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0);
228669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mVelocityTracker.addMovement(ev);
228769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        ev.recycle();
228869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragBeginTime = time;
228969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        return true;
229069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
229169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
229269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
229369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * End a fake drag of the pager.
229469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
229569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
229669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
229769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
229869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public void endFakeDrag() {
229969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (!mFakeDragging) {
230069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
230169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
230269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
230369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final VelocityTracker velocityTracker = mVelocityTracker;
230469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
23050f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell        int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
230669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell                velocityTracker, mActivePointerId);
230769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mPopulatePending = true;
2308becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu        final int width = getClientWidth();
2309035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final int scrollX = getScrollX();
2310a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo ii = infoForCurrentScrollPosition();
2311a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int currentPage = ii.position;
2312a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
2313a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int totalDelta = (int) (mLastMotionX - mInitialMotionX);
2314a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
2315a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                totalDelta);
2316035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        setCurrentItemInternal(nextPage, true, true, initialVelocity);
231769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        endDrag();
231869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
231969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragging = false;
232069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
232169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
232269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
232369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first.
232469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
232569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @param xOffset Offset in pixels to drag by.
232669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
232769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
232869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
232969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public void fakeDragBy(float xOffset) {
233069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (!mFakeDragging) {
233169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
233269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
233369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
233469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mLastMotionX += xOffset;
2335a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2336a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float oldScrollX = getScrollX();
23370f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell        float scrollX = oldScrollX - xOffset;
2338becb552984e4693c87f5f0ae38b6ebf4f719b740Dake Gu        final int width = getClientWidth();
233969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
2340a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float leftBound = width * mFirstOffset;
2341a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float rightBound = width * mLastOffset;
2342a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2343a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo firstItem = mItems.get(0);
2344a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
2345a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (firstItem.position != 0) {
2346a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            leftBound = firstItem.offset * width;
2347a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
2348a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (lastItem.position != mAdapter.getCount() - 1) {
2349a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            rightBound = lastItem.offset * width;
2350a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
2351a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
235269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (scrollX < leftBound) {
235369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            scrollX = leftBound;
235469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        } else if (scrollX > rightBound) {
235569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            scrollX = rightBound;
235669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
235769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        // Don't lose the rounded component
235869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mLastMotionX += scrollX - (int) scrollX;
235969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        scrollTo((int) scrollX, getScrollY());
23608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        pageScrolled((int) scrollX);
236169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
236269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        // Synthesize an event for the VelocityTracker.
236369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final long time = SystemClock.uptimeMillis();
236469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE,
236569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell                mLastMotionX, 0, 0);
236669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mVelocityTracker.addMovement(ev);
236769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        ev.recycle();
236869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
236969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
237069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
237169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Returns true if a fake drag is in progress.
237269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
237369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @return true if currently in a fake drag, false otherwise.
237469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
237569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
237669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
237769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
237869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
237969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public boolean isFakeDragging() {
238069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        return mFakeDragging;
238169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
238269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
2383d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void onSecondaryPointerUp(MotionEvent ev) {
2384d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int pointerIndex = MotionEventCompat.getActionIndex(ev);
2385d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
2386d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (pointerId == mActivePointerId) {
2387d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // This was our active pointer going up. Choose a new
2388d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // active pointer and adjust accordingly.
2389d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
2390d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);
2391d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
2392d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mVelocityTracker != null) {
2393d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mVelocityTracker.clear();
2394d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
2395d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2396d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
2397d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void endDrag() {
2399d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mIsBeingDragged = false;
2400d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mIsUnableToDrag = false;
2401d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2402d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mVelocityTracker != null) {
2403d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker.recycle();
2404d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker = null;
2405d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2406d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
2407d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2408d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void setScrollingCacheEnabled(boolean enabled) {
2409d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mScrollingCacheEnabled != enabled) {
2410d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mScrollingCacheEnabled = enabled;
2411d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (USE_CACHE) {
2412d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int size = getChildCount();
2413d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                for (int i = 0; i < size; ++i) {
2414d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final View child = getChildAt(i);
2415d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    if (child.getVisibility() != GONE) {
2416d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        child.setDrawingCacheEnabled(enabled);
2417d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    }
2418d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
2419d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
2420d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2421d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
24223661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2423aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette    public boolean canScrollHorizontally(int direction) {
2424aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette        if (mAdapter == null) {
2425aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette            return false;
2426aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette        }
2427aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette
2428aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette        final int width = getClientWidth();
2429aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette        final int scrollX = getScrollX();
2430aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette        if (direction < 0) {
2431aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette            return (scrollX > (int) (width * mFirstOffset));
2432aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette        } else if (direction > 0) {
2433aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette            return (scrollX < (int) (width * mLastOffset));
2434aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette        } else {
2435aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette            return false;
2436aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette        }
2437aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette    }
2438aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette
2439bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell    /**
2440cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * Tests scrollability within child views of v given a delta of dx.
2441bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     *
2442bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param v View to test for horizontal scrollability
2443bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
2444bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     *               or just its children (false).
2445bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param dx Delta scrolled in pixels
2446cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param x X coordinate of the active touch point
2447bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param y Y coordinate of the active touch point
2448cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @return true if child views of v can be scrolled by delta of dx.
2449bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     */
2450cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
2451bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        if (v instanceof ViewGroup) {
2452bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final ViewGroup group = (ViewGroup) v;
2453bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int scrollX = v.getScrollX();
2454bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int scrollY = v.getScrollY();
2455bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int count = group.getChildCount();
2456bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            // Count backwards - let topmost views consume scroll distance first.
2457bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            for (int i = count - 1; i >= 0; i--) {
2458bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                // TODO: Add versioned support here for transformed views.
2459bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                // This will not work for transformed views in Honeycomb+
2460bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                final View child = group.getChildAt(i);
2461bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
2462bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
2463bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
2464bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                                y + scrollY - child.getTop())) {
2465bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    return true;
2466bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                }
2467bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            }
2468bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        }
2469bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
2470bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        return checkV && ViewCompat.canScrollHorizontally(v, -dx);
2471bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell    }
2472bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
2473481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    @Override
24742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean dispatchKeyEvent(KeyEvent event) {
24752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // Let the focused view and/or our descendants get the key first
24762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
24772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
24782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
24792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
24802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * You can call this function yourself to have the scroll view perform
24812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * scrolling from a key event, just as if the event had been dispatched to
24822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * it by the view hierarchy.
24832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     *
24842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * @param event The key event to execute.
24852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * @return Return true if the event was handled, else false.
24862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
24872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean executeKeyEvent(KeyEvent event) {
24882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        boolean handled = false;
24892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (event.getAction() == KeyEvent.ACTION_DOWN) {
24902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            switch (event.getKeyCode()) {
24912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_DPAD_LEFT:
24922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = arrowScroll(FOCUS_LEFT);
24932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
24942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_DPAD_RIGHT:
24952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = arrowScroll(FOCUS_RIGHT);
24962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
24972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_TAB:
24985de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                    if (Build.VERSION.SDK_INT >= 11) {
24995de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD
25005de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        // before Android 3.0. Ignore the tab key on those devices.
25015de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        if (KeyEventCompat.hasNoModifiers(event)) {
25025de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                            handled = arrowScroll(FOCUS_FORWARD);
25035de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {
25045de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                            handled = arrowScroll(FOCUS_BACKWARD);
25055de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        }
25062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
25072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
25082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
25092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
25102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return handled;
25112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
25122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
25132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean arrowScroll(int direction) {
25142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        View currentFocused = findFocus();
251531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell        if (currentFocused == this) {
251631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell            currentFocused = null;
251731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell        } else if (currentFocused != null) {
251831dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell            boolean isChild = false;
251931dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell            for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
252031dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                    parent = parent.getParent()) {
252131dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                if (parent == this) {
252231dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                    isChild = true;
252331dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                    break;
252431dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                }
252531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell            }
252631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell            if (!isChild) {
252731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                // This would cause the focus search down below to fail in fun ways.
252831dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                final StringBuilder sb = new StringBuilder();
252931dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                sb.append(currentFocused.getClass().getSimpleName());
253031dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
253131dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                        parent = parent.getParent()) {
253231dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                    sb.append(" => ").append(parent.getClass().getSimpleName());
253331dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                }
253431dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                Log.e(TAG, "arrowScroll tried to find focus based on non-child " +
253531dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                        "current focused view " + sb.toString());
253631dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell                currentFocused = null;
253731dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell            }
253831dac59d77ff5c1e1ae2c425fa5fc939c6ec15cdAdam Powell        }
25392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
25402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        boolean handled = false;
25412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
25422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,
25432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                direction);
25442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (nextFocused != null && nextFocused != currentFocused) {
25452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (direction == View.FOCUS_LEFT) {
25462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // If there is nothing to the left, or this is causing us to
25472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // jump to the right, then what we really want to do is page left.
2548dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
2549dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
2550dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                if (currentFocused != null && nextLeft >= currLeft) {
25512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = pageLeft();
25522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                } else {
25532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = nextFocused.requestFocus();
25542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
25552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            } else if (direction == View.FOCUS_RIGHT) {
25562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // If there is nothing to the right, or this is causing us to
25572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // jump to the left, then what we really want to do is page right.
2558dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
2559dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
2560dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                if (currentFocused != null && nextLeft <= currLeft) {
25612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = pageRight();
25622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                } else {
25632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = nextFocused.requestFocus();
25642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
25652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
25662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {
25672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Trying to move left and nothing there; try to page.
25682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            handled = pageLeft();
25692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {
25702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Trying to move right and nothing there; try to page.
25712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            handled = pageRight();
25722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
25732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (handled) {
25742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
25752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
25762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return handled;
25772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
25782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
2579dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell    private Rect getChildRectInPagerCoordinates(Rect outRect, View child) {
2580dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        if (outRect == null) {
2581dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect = new Rect();
2582dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        }
2583efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell        if (child == null) {
2584efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell            outRect.set(0, 0, 0, 0);
2585efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell            return outRect;
2586efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell        }
2587dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        outRect.left = child.getLeft();
2588dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        outRect.right = child.getRight();
2589dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        outRect.top = child.getTop();
2590dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        outRect.bottom = child.getBottom();
2591dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell
2592dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        ViewParent parent = child.getParent();
2593dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        while (parent instanceof ViewGroup && parent != this) {
2594dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            final ViewGroup group = (ViewGroup) parent;
2595dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect.left += group.getLeft();
2596dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect.right += group.getRight();
2597dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect.top += group.getTop();
2598dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect.bottom += group.getBottom();
2599dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell
2600dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            parent = group.getParent();
2601dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        }
2602dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        return outRect;
2603dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell    }
2604dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell
26052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    boolean pageLeft() {
26062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (mCurItem > 0) {
26072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            setCurrentItem(mCurItem-1, true);
26082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return true;
26092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
26102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
26112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
26122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
26132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    boolean pageRight() {
2614218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) {
26152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            setCurrentItem(mCurItem+1, true);
26162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return true;
26172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
26182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
26192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
26202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
26212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
26222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be focusable.
26232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
26242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
26252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
26262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        final int focusableCount = views.size();
26272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
26282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        final int descendantFocusability = getDescendantFocusability();
26292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
26302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
26312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            for (int i = 0; i < getChildCount(); i++) {
26322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                final View child = getChildAt(i);
26332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (child.getVisibility() == VISIBLE) {
26342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    ItemInfo ii = infoForChild(child);
26352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (ii != null && ii.position == mCurItem) {
26362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        child.addFocusables(views, direction, focusableMode);
26372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
26382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
26392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
26402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
26412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
26422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // we add ourselves (if focusable) in all cases except for when we are
26432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
26442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // to avoid the focus search finding layouts when a more precise search
26452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // among the focusable children would be more interesting.
26462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (
26472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
26482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // No focusable descendants
26492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                (focusableCount == views.size())) {
26502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Note that we can't call the superclass here, because it will
26512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // add all views in.  So we need to do the same thing View does.
26522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (!isFocusable()) {
26532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return;
26542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
26552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE &&
26562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    isInTouchMode() && !isFocusableInTouchMode()) {
26572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return;
26582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
26592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (views != null) {
26602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                views.add(this);
26612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
26622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
26632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
26642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
26652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
26662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be touchable.
26672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
26682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
26692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public void addTouchables(ArrayList<View> views) {
26702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // Note that we don't call super.addTouchables(), which means that
26712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // we don't call View.addTouchables().  This is okay because a ViewPager
26722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // is itself not touchable.
26732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        for (int i = 0; i < getChildCount(); i++) {
26742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            final View child = getChildAt(i);
26752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (child.getVisibility() == VISIBLE) {
26762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                ItemInfo ii = infoForChild(child);
26772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (ii != null && ii.position == mCurItem) {
26782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    child.addTouchables(views);
26792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
26802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
26812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
26822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
26832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
26842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
26852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be focusable.
26862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
26872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
26882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    protected boolean onRequestFocusInDescendants(int direction,
26892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            Rect previouslyFocusedRect) {
26902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int index;
26912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int increment;
26922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int end;
26932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int count = getChildCount();
26942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if ((direction & FOCUS_FORWARD) != 0) {
26952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            index = 0;
26962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            increment = 1;
26972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            end = count;
26982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else {
26992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            index = count - 1;
27002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            increment = -1;
27012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            end = -1;
27022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
27032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        for (int i = index; i != end; i += increment) {
27042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            View child = getChildAt(i);
27052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (child.getVisibility() == VISIBLE) {
27062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                ItemInfo ii = infoForChild(child);
27072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (ii != null && ii.position == mCurItem) {
27082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (child.requestFocus(direction, previouslyFocusedRect)) {
27092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        return true;
27102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
27112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
27122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
2713481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        }
27142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
2715481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    }
2716481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2717481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    @Override
2718481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
2719109e561bfa6720a7043a28dc265297d915170954Alan Viverette        // Dispatch scroll events from this ViewPager.
2720109e561bfa6720a7043a28dc265297d915170954Alan Viverette        if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) {
2721109e561bfa6720a7043a28dc265297d915170954Alan Viverette            return super.dispatchPopulateAccessibilityEvent(event);
2722109e561bfa6720a7043a28dc265297d915170954Alan Viverette        }
2723481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2724109e561bfa6720a7043a28dc265297d915170954Alan Viverette        // Dispatch all other accessibility events from the current page.
2725481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        final int childCount = getChildCount();
2726481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        for (int i = 0; i < childCount; i++) {
2727481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            final View child = getChildAt(i);
2728481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            if (child.getVisibility() == VISIBLE) {
2729481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                final ItemInfo ii = infoForChild(child);
2730481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                if (ii != null && ii.position == mCurItem &&
2731481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                        child.dispatchPopulateAccessibilityEvent(event)) {
2732481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                    return true;
2733481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                }
2734481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            }
2735481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        }
2736481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2737481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        return false;
2738481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    }
2739481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
27408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
27418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
27428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return new LayoutParams();
27438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
27448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
27458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
27468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
27478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return generateDefaultLayoutParams();
27488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
27498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
27508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
27518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
27528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return p instanceof LayoutParams && super.checkLayoutParams(p);
27538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
27548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
27558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
27568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
27571ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        return new LayoutParams(getContext(), attrs);
27588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
27598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
276025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov    class MyAccessibilityDelegate extends AccessibilityDelegateCompat {
276125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
276225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        @Override
276325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
276425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            super.onInitializeAccessibilityEvent(host, event);
276525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            event.setClassName(ViewPager.class.getName());
27669a95c60a9c9fcc7d5ca0f9aeaede854d2a47a824Ying Wang            final AccessibilityRecordCompat recordCompat = AccessibilityRecordCompat.obtain();
2767109e561bfa6720a7043a28dc265297d915170954Alan Viverette            recordCompat.setScrollable(canScroll());
2768e4578af7dfd6ae3f85435a569ed8d5107bf20ec3Svetoslav            if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED
2769e4578af7dfd6ae3f85435a569ed8d5107bf20ec3Svetoslav                    && mAdapter != null) {
2770109e561bfa6720a7043a28dc265297d915170954Alan Viverette                recordCompat.setItemCount(mAdapter.getCount());
2771109e561bfa6720a7043a28dc265297d915170954Alan Viverette                recordCompat.setFromIndex(mCurItem);
2772109e561bfa6720a7043a28dc265297d915170954Alan Viverette                recordCompat.setToIndex(mCurItem);
2773109e561bfa6720a7043a28dc265297d915170954Alan Viverette            }
277425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        }
277525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
277625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        @Override
277725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
277825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            super.onInitializeAccessibilityNodeInfo(host, info);
277925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            info.setClassName(ViewPager.class.getName());
2780109e561bfa6720a7043a28dc265297d915170954Alan Viverette            info.setScrollable(canScroll());
2781aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette            if (canScrollHorizontally(1)) {
278225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
278325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            }
2784aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette            if (canScrollHorizontally(-1)) {
278525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
278625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            }
278725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        }
278825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
278925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        @Override
279025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        public boolean performAccessibilityAction(View host, int action, Bundle args) {
279125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            if (super.performAccessibilityAction(host, action, args)) {
279225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                return true;
279325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            }
279425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            switch (action) {
279525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: {
2796aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette                    if (canScrollHorizontally(1)) {
279725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                        setCurrentItem(mCurItem + 1);
279825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                        return true;
279925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                    }
280025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                } return false;
280125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: {
2802aa35c4c3bf312c24b48dc6d2af430b5bacebfaf0Alan Viverette                    if (canScrollHorizontally(-1)) {
280325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                        setCurrentItem(mCurItem - 1);
280425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                        return true;
280525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                    }
280625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                } return false;
280725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            }
280825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            return false;
280925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        }
2810109e561bfa6720a7043a28dc265297d915170954Alan Viverette
2811109e561bfa6720a7043a28dc265297d915170954Alan Viverette        private boolean canScroll() {
2812109e561bfa6720a7043a28dc265297d915170954Alan Viverette            return (mAdapter != null) && (mAdapter.getCount() > 1);
2813109e561bfa6720a7043a28dc265297d915170954Alan Viverette        }
281425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov    }
281525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
28168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private class PagerObserver extends DataSetObserver {
28178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        @Override
28188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onChanged() {
28198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            dataSetChanged();
28208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
28213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
28228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onInvalidated() {
28233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            dataSetChanged();
28243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
28253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
28268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
28277dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn    /**
28287dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * Layout parameters that should be supplied for views added to a
28297dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * ViewPager.
28307dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     */
28318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public static class LayoutParams extends ViewGroup.LayoutParams {
28328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        /**
28338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * true if this view is a decoration on the pager itself and not
28348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * a view supplied by the adapter.
28358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         */
28368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public boolean isDecor;
28378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2838a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
28393d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn         * Gravity setting for use on decor views only:
28407dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn         * Where to position the view page within the overall ViewPager
28417dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn         * container; constants are defined in {@link android.view.Gravity}.
2842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
28438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public int gravity;
28448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2845a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
2846a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * Width as a 0-1 multiplier of the measured pager width
2847a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
28487e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        float widthFactor = 0.f;
2849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
2851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * true if this view was added during layout and needs to be measured
2852a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * before being positioned.
2853a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
28547e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        boolean needsMeasure;
28557e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell
28567e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        /**
28577e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell         * Adapter position this view is for if !isDecor
28587e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell         */
28597e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        int position;
28607e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell
28617e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        /**
28627e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell         * Current child index within the ViewPager that this view occupies
28637e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell         */
28647e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        int childIndex;
2865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
28668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public LayoutParams() {
28678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            super(FILL_PARENT, FILL_PARENT);
28688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
28698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
28708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public LayoutParams(Context context, AttributeSet attrs) {
28718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            super(context, attrs);
28728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
28738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
2874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            gravity = a.getInteger(0, Gravity.TOP);
28758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            a.recycle();
28768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
28778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
28787e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell
28797e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell    static class ViewPositionComparator implements Comparator<View> {
28807e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        @Override
28817e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        public int compare(View lhs, View rhs) {
28827e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            final LayoutParams llp = (LayoutParams) lhs.getLayoutParams();
28837e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams();
28847e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            if (llp.isDecor != rlp.isDecor) {
28857e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell                return llp.isDecor ? 1 : -1;
28867e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            }
28877e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell            return llp.position - rlp.position;
28887e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell        }
28897e464c3f9ff67d08c61f1c7a57dee0532c3c9449Adam Powell    }
2890d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn}
2891