ViewPager.java revision efea2e772645ccd2d0de3e92fa8382d5444eab11
1d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/*
2d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project
3d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn *
4d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * you may not use this file except in compliance with the License.
6d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * You may obtain a copy of the License at
7d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn *
8d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn *
10d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * See the License for the specific language governing permissions and
14d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * limitations under the License.
15d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */
16d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
175c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornpackage android.support.v4.view;
18d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
19481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.content.Context;
208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.content.res.TypedArray;
218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.database.DataSetObserver;
22560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.graphics.Canvas;
23481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.graphics.Rect;
24329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powellimport android.graphics.drawable.Drawable;
255de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powellimport android.os.Build;
2625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.os.Bundle;
27d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcel;
28d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.os.Parcelable;
2969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powellimport android.os.SystemClock;
305c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompat;
315c1637087453de15e31861f073eae5133c4e9f7bDianne Hackbornimport android.support.v4.os.ParcelableCompatCreatorCallbacks;
3225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganovimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
33560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powellimport android.support.v4.widget.EdgeEffectCompat;
34d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.AttributeSet;
35d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.util.Log;
362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.FocusFinder;
378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powellimport android.view.Gravity;
382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.KeyEvent;
39d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.MotionEvent;
402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackbornimport android.view.SoundEffectConstants;
41d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.VelocityTracker;
42d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.View;
43d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewConfiguration;
44d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.view.ViewGroup;
45218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackbornimport android.view.ViewParent;
46481243c175651c5de0741ab9390eb10f5b024d98Adam Powellimport android.view.accessibility.AccessibilityEvent;
471cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powellimport android.view.animation.Interpolator;
48d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport android.widget.Scroller;
49d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
50d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackbornimport java.util.ArrayList;
5166c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Collections;
5266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Phamimport java.util.Comparator;
53d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
54d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn/**
55d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn * Layout manager that allows the user to flip left and right
565c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * through pages of data.  You supply an implementation of a
575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * {@link PagerAdapter} to generate the pages that the view shows.
585c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn *
595c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * <p>Note this class is currently under early design and
605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * development.  The API will likely change in later updates of
615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * the compatibility library, requiring changes to the source code
625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn * of apps when they are compiled against the newer version.</p>
637dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
647dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment},
657dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which is a convenient way to supply and manage the lifecycle of each page.
667dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * There are standard adapters implemented for using fragments with the ViewPager,
677dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * which cover the most common use cases.  These are
687dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentPagerAdapter},
697dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v4.app.FragmentStatePagerAdapter},
707dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentPagerAdapter}, and
717dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@link android.support.v13.app.FragmentStatePagerAdapter}; each of these
727dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * classes have simple code showing how to build a full user interface
737dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with them.
747dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
757dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * <p>Here is a more complicated example of ViewPager, using it in conjuction
767dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * with {@link android.app.ActionBar} tabs.  You can find other examples of using
777dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code.
787dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *
797dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
807dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn *      complete}
81d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn */
82ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackbornpublic class ViewPager extends ViewGroup {
833661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private static final String TAG = "ViewPager";
84d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final boolean DEBUG = false;
85d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
86d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final boolean USE_CACHE = false;
87d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
8829a6184d74279156a9297dc67398712fb047fdc0Adam Powell    private static final int DEFAULT_OFFSCREEN_PAGES = 1;
891cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    private static final int MAX_SETTLE_DURATION = 600; // ms
90035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
9129a6184d74279156a9297dc67398712fb047fdc0Adam Powell
928f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private static final int DEFAULT_GUTTER_SIZE = 16; // dips
938f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell
948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private static final int[] LAYOUT_ATTRS = new int[] {
958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        android.R.attr.layout_gravity
968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    };
978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
98d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    static class ItemInfo {
99ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        Object object;
100d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int position;
1014c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        boolean scrolling;
102a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float widthFactor;
103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float offset;
104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
105d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
10666c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham    private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){
10766c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        @Override
10866c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        public int compare(ItemInfo lhs, ItemInfo rhs) {
10966c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham            return lhs.position - rhs.position;
110a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
111a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    };
11266c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham
1131cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    private static final Interpolator sInterpolator = new Interpolator() {
1141cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        public float getInterpolation(float t) {
1151cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell            t -= 1.0f;
116035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            return t * t * t * t * t + 1.0f;
1171cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        }
1181cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    };
1191cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
121a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private final ItemInfo mTempItem = new ItemInfo();
122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
123dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell    private final Rect mTempRect = new Rect();
124dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell
125ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    private PagerAdapter mAdapter;
1263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private int mCurItem;   // Index of currently displayed page.
127d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mRestoredCurItem = -1;
128ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    private Parcelable mRestoredAdapterState = null;
1295c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn    private ClassLoader mRestoredClassLoader = null;
130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private Scroller mScroller;
1318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private PagerObserver mObserver;
132d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
133329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private int mPageMargin;
134329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private Drawable mMarginDrawable;
1358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mTopPageBounds;
1368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mBottomPageBounds;
137329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
138a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // Offsets of the first and last items, if known.
139a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // Set during population, used to determine if we are at the beginning
140a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    // or end of the pager data set during touch scrolling.
141a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private float mFirstOffset = -Float.MAX_VALUE;
142a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private float mLastOffset = Float.MAX_VALUE;
143a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mChildWidthMeasureSpec;
145d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mChildHeightMeasureSpec;
146d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mInLayout;
147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mScrollingCacheEnabled;
149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mPopulatePending;
15129a6184d74279156a9297dc67398712fb047fdc0Adam Powell    private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;
152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mIsBeingDragged;
154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private boolean mIsUnableToDrag;
1558f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private boolean mIgnoreGutter;
1568f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private int mDefaultGutterSize;
1578f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private int mGutterSize;
158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mTouchSlop;
159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private float mInitialMotionX;
160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Position of the last motion event.
162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private float mLastMotionX;
164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private float mLastMotionY;
165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * ID of the active pointer. This is used to retain consistency during
167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * drags/flings if multiple pointers are used.
168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mActivePointerId = INVALID_POINTER;
170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Sentinel value for no current active pointer.
172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Used by {@link #mActivePointerId}.
173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
174d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private static final int INVALID_POINTER = -1;
175d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
176d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
177d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Determines speed during touch scrolling
178d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
179d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private VelocityTracker mVelocityTracker;
180d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mMinimumVelocity;
181d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private int mMaximumVelocity;
182035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private int mFlingDistance;
183b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    private int mCloseEnough;
184b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell
185b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // If the pager is at least this close to its final position, complete the scroll
186b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // on touch down and let the user interact with the content inside instead of
187b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    // "catching" the flinging pager.
188b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell    private static final int CLOSE_ENOUGH = 2; // dp
189d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
19069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    private boolean mFakeDragging;
19169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    private long mFakeDragBeginTime;
19269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
193560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    private EdgeEffectCompat mLeftEdge;
194560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    private EdgeEffectCompat mRightEdge;
195560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
19697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    private boolean mFirstLayout = true;
197a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private boolean mNeedCalculatePageOffsets = false;
1988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private boolean mCalledSuper;
1998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private int mDecorChildCount;
20097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell
2013661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    private OnPageChangeListener mOnPageChangeListener;
2028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private OnPageChangeListener mInternalPageChangeListener;
2038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private OnAdapterChangeListener mAdapterChangeListener;
2043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    /**
20647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is in an idle, settled state. The current page
20747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * is fully in view and no animation is in progress.
20847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
20947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_IDLE = 0;
21047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
21147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
21247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is currently being dragged by the user.
21347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
21447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_DRAGGING = 1;
21547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
21647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
21747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     * Indicates that the pager is in the process of settling to a final position.
21847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell     */
21947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    public static final int SCROLL_STATE_SETTLING = 2;
22047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
22147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    private int mScrollState = SCROLL_STATE_IDLE;
22247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
22347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    /**
2243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * Callback interface for responding to changing state of the selected page.
2253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     */
2263661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public interface OnPageChangeListener {
22747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
2283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        /**
2293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * This method will be invoked when the current page is scrolled, either as part
2303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
2313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *
2323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param position Position index of the first page currently being displayed.
2333661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *                 Page position+1 will be visible if positionOffset is nonzero.
2343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
2353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param positionOffsetPixels Value in pixels indicating the offset from position.
2363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         */
2373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
2383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        /**
24047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * This method will be invoked when a new page becomes selected. Animation is not
24147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * necessarily complete.
2423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         *
2433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         * @param position Position index of the new selected page.
2443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell         */
2453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageSelected(int position);
24647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
24747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        /**
24847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * Called when the scroll state changes. Useful for discovering when the user
24947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * begins dragging, when the pager is automatically settling to the current page,
25047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * or when it is fully stopped/idle.
25147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         *
25247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @param state The new scroll state.
25347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_IDLE
25447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_DRAGGING
25547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         * @see ViewPager#SCROLL_STATE_SETTLING
25647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell         */
25747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        public void onPageScrollStateChanged(int state);
2583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
2593661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2603661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    /**
2613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * Simple implementation of the {@link OnPageChangeListener} interface with stub
2623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * implementations of each method. Extend this if you do not intend to override
2633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     * every method of {@link OnPageChangeListener}.
2643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell     */
2653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public static class SimpleOnPageChangeListener implements OnPageChangeListener {
2663661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
2673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
2683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // This space for rent
2693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
2703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2713661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
2723661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        public void onPageSelected(int position) {
2733661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // This space for rent
2743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
27547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
27647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        @Override
27747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        public void onPageScrollStateChanged(int state) {
27847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            // This space for rent
27947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
2803661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
2813661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
2838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Used internally to monitor when adapters are switched.
2848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
2858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    interface OnAdapterChangeListener {
2868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter);
2878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
2888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2891ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell    /**
2901ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     * Used internally to tag special types of child views that should be added as
2911ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     * pager decorations by default.
2921ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell     */
2931ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell    interface Decor {}
2941ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell
295ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public ViewPager(Context context) {
296d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super(context);
29747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        initViewPager();
298d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
299d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
300ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public ViewPager(Context context, AttributeSet attrs) {
301d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super(context, attrs);
30247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        initViewPager();
303d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
304d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
30547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    void initViewPager() {
306d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        setWillNotDraw(false);
3072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
3082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        setFocusable(true);
309560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        final Context context = getContext();
3101cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        mScroller = new Scroller(context, sInterpolator);
3111cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        final ViewConfiguration configuration = ViewConfiguration.get(context);
312d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
313d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
314d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
315560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        mLeftEdge = new EdgeEffectCompat(context);
316560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        mRightEdge = new EdgeEffectCompat(context);
3171cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
318035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final float density = context.getResources().getDisplayMetrics().density;
319035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
320b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell        mCloseEnough = (int) (CLOSE_ENOUGH * density);
3218f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);
32225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
32325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate());
32425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
32525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        if (ViewCompat.getImportantForAccessibility(this)
32625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
32725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            ViewCompat.setImportantForAccessibility(this,
32825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
32925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        }
330d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
331d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
33247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    private void setScrollState(int newState) {
33347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        if (mScrollState == newState) {
33447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            return;
33547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
33647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
33747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        mScrollState = newState;
33847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        if (mOnPageChangeListener != null) {
33947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            mOnPageChangeListener.onPageScrollStateChanged(newState);
34047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        }
34147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    }
34247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell
3438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
3448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a PagerAdapter that will supply views for this pager as needed.
3458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
3468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param adapter Adapter to use
3478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
348ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public void setAdapter(PagerAdapter adapter) {
3493661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (mAdapter != null) {
3508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapter.unregisterDataSetObserver(mObserver);
3510d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mAdapter.startUpdate(this);
3520d6d2990ddacd3f419879149137f09a30c061436Minh Pham            for (int i = 0; i < mItems.size(); i++) {
3530d6d2990ddacd3f419879149137f09a30c061436Minh Pham                final ItemInfo ii = mItems.get(i);
3540d6d2990ddacd3f419879149137f09a30c061436Minh Pham                mAdapter.destroyItem(this, ii.position, ii.object);
3550d6d2990ddacd3f419879149137f09a30c061436Minh Pham            }
3560d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mAdapter.finishUpdate(this);
3570d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mItems.clear();
358a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            removeNonDecorViews();
3590d6d2990ddacd3f419879149137f09a30c061436Minh Pham            mCurItem = 0;
360871a68b5daafd810623d680207652f87eb2d11ccMinh Pham            scrollTo(0, 0);
3613661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
3623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
3638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final PagerAdapter oldAdapter = mAdapter;
364d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mAdapter = adapter;
365d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
366d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter != null) {
3673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (mObserver == null) {
3688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mObserver = new PagerObserver();
3693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
3708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapter.registerDataSetObserver(mObserver);
371d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mPopulatePending = false;
37291eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell            mFirstLayout = true;
373d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mRestoredCurItem >= 0) {
3745c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
375d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                setCurrentItemInternal(mRestoredCurItem, false, true);
376d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mRestoredCurItem = -1;
377ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn                mRestoredAdapterState = null;
3785c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                mRestoredClassLoader = null;
379d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            } else {
380d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                populate();
381d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
382d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
3838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
3848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mAdapterChangeListener != null && oldAdapter != adapter) {
3858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
3868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
387d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
388d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
389a7aea206661d601755bfac4165092d9130cba2bcAdam Powell    private void removeNonDecorViews() {
390a7aea206661d601755bfac4165092d9130cba2bcAdam Powell        for (int i = 0; i < getChildCount(); i++) {
391a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            final View child = getChildAt(i);
392a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
393a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            if (!lp.isDecor) {
394a7aea206661d601755bfac4165092d9130cba2bcAdam Powell                removeViewAt(i);
395a7aea206661d601755bfac4165092d9130cba2bcAdam Powell                i--;
396a7aea206661d601755bfac4165092d9130cba2bcAdam Powell            }
397a7aea206661d601755bfac4165092d9130cba2bcAdam Powell        }
398a7aea206661d601755bfac4165092d9130cba2bcAdam Powell    }
399a7aea206661d601755bfac4165092d9130cba2bcAdam Powell
4008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
4018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Retrieve the current adapter supplying pages.
4028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
4038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @return The currently registered PagerAdapter
4048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
405ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    public PagerAdapter getAdapter() {
406d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return mAdapter;
407d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
408d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
4098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    void setOnAdapterChangeListener(OnAdapterChangeListener listener) {
4108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mAdapterChangeListener = listener;
4118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
4128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
41397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    /**
41497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * Set the currently selected page. If the ViewPager has already been through its first
41591eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell     * layout with its current adapter there will be a smooth animated transition between
41691eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell     * the current item and the specified item.
41797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     *
41897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param item Item index to select
41997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     */
420d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void setCurrentItem(int item) {
421d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mPopulatePending = false;
42297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        setCurrentItemInternal(item, !mFirstLayout, false);
42397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    }
42497d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell
42597d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    /**
42697d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * Set the currently selected page.
42797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     *
42897d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param item Item index to select
42997d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
43097d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell     */
43197d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell    public void setCurrentItem(int item, boolean smoothScroll) {
43297d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mPopulatePending = false;
43397d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        setCurrentItemInternal(item, smoothScroll, false);
434d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
435d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
436bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki    public int getCurrentItem() {
437bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki        return mCurItem;
438bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki    }
439bd4398ce660db91dabde5db1e87890d5df0b0823Makoto Onuki
440d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
4411cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        setCurrentItemInternal(item, smoothScroll, always, 0);
4421cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
4431cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
4441cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
445d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter == null || mAdapter.getCount() <= 0) {
446d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
447d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
448d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
449d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (!always && mCurItem == item && mItems.size() != 0) {
450d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
451d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
452d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
4538d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell
454d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (item < 0) {
455d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            item = 0;
456d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else if (item >= mAdapter.getCount()) {
457d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            item = mAdapter.getCount() - 1;
458d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
45929a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int pageLimit = mOffscreenPageLimit;
46029a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
4614c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // We are doing a jump by more than one page.  To avoid
4624c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // glitches, we want to keep all current pages in the view
4634c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // until the scroll ends.
4644c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            for (int i=0; i<mItems.size(); i++) {
4654c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                mItems.get(i).scrolling = true;
4664c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            }
4674c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
46847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        final boolean dispatchSelected = mCurItem != item;
469a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        populate(item);
470a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo curInfo = infoForPosition(item);
47131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        int destX = 0;
47231bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        if (curInfo != null) {
47331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            final int width = getWidth();
47431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            destX = (int) (width * Math.max(mFirstOffset,
47531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                    Math.min(curInfo.offset, mLastOffset)));
47631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        }
477d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (smoothScroll) {
4781cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell            smoothScrollTo(destX, 0, velocity);
47947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            if (dispatchSelected && mOnPageChangeListener != null) {
48047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                mOnPageChangeListener.onPageSelected(item);
48147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            }
4828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (dispatchSelected && mInternalPageChangeListener != null) {
4838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mInternalPageChangeListener.onPageSelected(item);
4848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
485d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
48647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            if (dispatchSelected && mOnPageChangeListener != null) {
4873661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mOnPageChangeListener.onPageSelected(item);
4883661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
4898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (dispatchSelected && mInternalPageChangeListener != null) {
4908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                mInternalPageChangeListener.onPageSelected(item);
4918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
49247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            completeScroll();
493329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            scrollTo(destX, 0);
494d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
495d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
496d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
4978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
4988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a listener that will be invoked whenever the page changes or is incrementally
4998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * scrolled. See {@link OnPageChangeListener}.
5008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
5018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param listener Listener to set
5028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
5033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    public void setOnPageChangeListener(OnPageChangeListener listener) {
5043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        mOnPageChangeListener = listener;
5053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
5063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
507d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    /**
5088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * Set a separate OnPageChangeListener for internal use by the support library.
5098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
5108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param listener Listener to set
5118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @return The old listener that was set, if any.
5128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
5138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {
5148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        OnPageChangeListener oldListener = mInternalPageChangeListener;
5158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mInternalPageChangeListener = listener;
5168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return oldListener;
5178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
5188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
5198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
52029a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * Returns the number of pages that will be retained to either side of the
52129a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * current page in the view hierarchy in an idle state. Defaults to 1.
52229a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
52329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @return How many pages will be kept offscreen on either side
52429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @see #setOffscreenPageLimit(int)
52529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     */
52629a6184d74279156a9297dc67398712fb047fdc0Adam Powell    public int getOffscreenPageLimit() {
52729a6184d74279156a9297dc67398712fb047fdc0Adam Powell        return mOffscreenPageLimit;
52829a6184d74279156a9297dc67398712fb047fdc0Adam Powell    }
52929a6184d74279156a9297dc67398712fb047fdc0Adam Powell
53029a6184d74279156a9297dc67398712fb047fdc0Adam Powell    /**
53129a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * Set the number of pages that should be retained to either side of the
53229a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * current page in the view hierarchy in an idle state. Pages beyond this
53329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * limit will be recreated from the adapter when needed.
53429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
53529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * <p>This is offered as an optimization. If you know in advance the number
53629a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * of pages you will need to support or have lazy-loading mechanisms in place
53729a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * on your pages, tweaking this setting can have benefits in perceived smoothness
53829a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * of paging animations and interaction. If you have a small number of pages (3-4)
53929a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * that you can keep active all at once, less time will be spent in layout for
54029a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * newly created view subtrees as the user pages back and forth.</p>
54129a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
54229a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * <p>You should keep this limit low, especially if your pages have complex layouts.
54329a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * This setting defaults to 1.</p>
54429a6184d74279156a9297dc67398712fb047fdc0Adam Powell     *
54529a6184d74279156a9297dc67398712fb047fdc0Adam Powell     * @param limit How many pages will be kept offscreen in an idle state.
54629a6184d74279156a9297dc67398712fb047fdc0Adam Powell     */
54729a6184d74279156a9297dc67398712fb047fdc0Adam Powell    public void setOffscreenPageLimit(int limit) {
54829a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (limit < DEFAULT_OFFSCREEN_PAGES) {
54929a6184d74279156a9297dc67398712fb047fdc0Adam Powell            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
55029a6184d74279156a9297dc67398712fb047fdc0Adam Powell                    DEFAULT_OFFSCREEN_PAGES);
55129a6184d74279156a9297dc67398712fb047fdc0Adam Powell            limit = DEFAULT_OFFSCREEN_PAGES;
55229a6184d74279156a9297dc67398712fb047fdc0Adam Powell        }
55329a6184d74279156a9297dc67398712fb047fdc0Adam Powell        if (limit != mOffscreenPageLimit) {
55429a6184d74279156a9297dc67398712fb047fdc0Adam Powell            mOffscreenPageLimit = limit;
55529a6184d74279156a9297dc67398712fb047fdc0Adam Powell            populate();
55629a6184d74279156a9297dc67398712fb047fdc0Adam Powell        }
55729a6184d74279156a9297dc67398712fb047fdc0Adam Powell    }
55829a6184d74279156a9297dc67398712fb047fdc0Adam Powell
55929a6184d74279156a9297dc67398712fb047fdc0Adam Powell    /**
560329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set the margin between pages.
561329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
562329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param marginPixels Distance between adjacent pages in pixels
563329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #getPageMargin()
564329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #setPageMarginDrawable(Drawable)
565329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @see #setPageMarginDrawable(int)
566329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
567329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMargin(int marginPixels) {
568329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final int oldMargin = mPageMargin;
569329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        mPageMargin = marginPixels;
570329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
571329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final int width = getWidth();
572329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        recomputeScrollPosition(width, width, marginPixels, oldMargin);
573329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
574329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        requestLayout();
575329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
576329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
577329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
578329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Return the margin between pages.
579329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
580329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @return The size of the margin in pixels
581329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
582329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public int getPageMargin() {
583329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        return mPageMargin;
584329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
585329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
586329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
587329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set a drawable that will be used to fill the margin between pages.
588329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
589329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param d Drawable to display between pages
590329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
591329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMarginDrawable(Drawable d) {
592329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        mMarginDrawable = d;
593329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        if (d != null) refreshDrawableState();
594329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        setWillNotDraw(d == null);
595329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        invalidate();
596329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
597329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
598329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
599329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * Set a drawable that will be used to fill the margin between pages.
600329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     *
601329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     * @param resId Resource ID of a drawable to display between pages
602329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell     */
603329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    public void setPageMarginDrawable(int resId) {
604329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        setPageMarginDrawable(getContext().getResources().getDrawable(resId));
605329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
606329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
607329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
608329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected boolean verifyDrawable(Drawable who) {
609329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        return super.verifyDrawable(who) || who == mMarginDrawable;
610329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
611329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
612329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
613329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected void drawableStateChanged() {
614329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        super.drawableStateChanged();
615329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        final Drawable d = mMarginDrawable;
616329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        if (d != null && d.isStateful()) {
617329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            d.setState(getDrawableState());
618329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
619329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
620329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
6211cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // We want the duration of the page snap animation to be influenced by the distance that
6221cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // the screen has to travel, however, we don't want this duration to be effected in a
6231cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
6241cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    // of travel has on the overall snap duration.
6251cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    float distanceInfluenceForSnapDuration(float f) {
6261cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        f -= 0.5f; // center the values about 0.
6271cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        f *= 0.3f * Math.PI / 2.0f;
6281cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        return (float) Math.sin(f);
6291cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
6301cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
631329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    /**
632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     *
634cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param x the number of pixels to scroll by on the X axis
635cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param y the number of pixels to scroll by on the Y axis
636d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn     */
637d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void smoothScrollTo(int x, int y) {
6381cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        smoothScrollTo(x, y, 0);
6391cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    }
6401cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
6411cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    /**
6421cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
6431cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     *
6441cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param x the number of pixels to scroll by on the X axis
6451cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param y the number of pixels to scroll by on the Y axis
6461cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)
6471cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell     */
6481cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell    void smoothScrollTo(int x, int y, int velocity) {
649d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (getChildCount() == 0) {
650d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Nothing to do.
651d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setScrollingCacheEnabled(false);
652d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
653d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
654d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int sx = getScrollX();
655d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int sy = getScrollY();
6563661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        int dx = x - sx;
6573661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        int dy = y - sy;
6583661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (dx == 0 && dy == 0) {
65947dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            completeScroll();
66031bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            populate();
6613040c142491acd4a09e7d0add073be0067aec2d5Adam Powell            setScrollState(SCROLL_STATE_IDLE);
6623661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            return;
6633661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
6643661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
6653661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        setScrollingCacheEnabled(true);
66647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        setScrollState(SCROLL_STATE_SETTLING);
6671cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
668035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final int width = getWidth();
669035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final int halfWidth = width / 2;
670035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
671035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final float distance = halfWidth + halfWidth *
672035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                distanceInfluenceForSnapDuration(distanceRatio);
6731cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
674035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        int duration = 0;
6751cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        velocity = Math.abs(velocity);
6761cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        if (velocity > 0) {
677035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
6781cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        } else {
679a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
680a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
681035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            duration = (int) ((pageDelta + 1) * 100);
6821cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        }
6831cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        duration = Math.min(duration, MAX_SETTLE_DURATION);
6841cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell
6851cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell        mScroller.startScroll(sx, sy, dx, dy, duration);
686b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell        ViewCompat.postInvalidateOnAnimation(this);
687d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
688d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
689a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    ItemInfo addNewItem(int position, int index) {
690d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ItemInfo ii = new ItemInfo();
691d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ii.position = position;
6925c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        ii.object = mAdapter.instantiateItem(this, position);
693a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ii.widthFactor = mAdapter.getPageWidth(position);
694a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (index < 0 || index >= mItems.size()) {
695d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mItems.add(ii);
696d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
697d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mItems.add(index, ii);
698d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
699a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        return ii;
700d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
701d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
7023661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    void dataSetChanged() {
7033661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        // This method only gets called if our observer is attached, so mAdapter is non-null.
7043661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7051a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell        boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 &&
7061a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell                mItems.size() < mAdapter.getCount();
7071e300b0aca2f34bfe65885c5405044cfe5585224Adam Powell        int newCurrItem = mCurItem;
7083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7099508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        boolean isUpdating = false;
7103661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        for (int i = 0; i < mItems.size(); i++) {
7113661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            final ItemInfo ii = mItems.get(i);
7123661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            final int newPos = mAdapter.getItemPosition(ii.object);
7133661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7143661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
7153661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                continue;
7163661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
7173661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7183661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (newPos == PagerAdapter.POSITION_NONE) {
7193661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mItems.remove(i);
7203661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                i--;
7219508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
7229508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                if (!isUpdating) {
7239508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                    mAdapter.startUpdate(this);
7249508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                    isUpdating = true;
7259508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell                }
7269508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
7273661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                mAdapter.destroyItem(this, ii.position, ii.object);
7283661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                needPopulate = true;
7293661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (mCurItem == ii.position) {
7313661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    // Keep the current item in the valid range
7323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1));
7331a1c2acbc15f8bc9dba05d09dcb18e340474e1c6Adam Powell                    needPopulate = true;
7343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
7353661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                continue;
7363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
7373661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (ii.position != newPos) {
7393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (ii.position == mCurItem) {
7403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    // Our current item changed position. Follow it.
7413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    newCurrItem = newPos;
7423661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
7433661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7443661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                ii.position = newPos;
7453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                needPopulate = true;
7463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            }
7473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
7483661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
7499508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        if (isUpdating) {
7509508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell            mAdapter.finishUpdate(this);
7519508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell        }
7529508e3e642f5093e3181b4d5a3777bd84eedbcc6Adam Powell
75366c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham        Collections.sort(mItems, COMPARATOR);
75466c0e6a0a5fd20c66b6c86133b8bd91fe303e430Minh Pham
755a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (needPopulate) {
756a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Reset our known page widths; populate will recompute them.
757a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int childCount = getChildCount();
758a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int i = 0; i < childCount; i++) {
759a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final View child = getChildAt(i);
760a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
761a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (!lp.isDecor) {
762a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    lp.widthFactor = 0.f;
763a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
764a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
765a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
766d84ef6c972b75c0ddeee88db2d66d40fff7519a8Adam Powell            setCurrentItemInternal(newCurrItem, false, true);
7673661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            requestLayout();
7683661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
7693661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
7703661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
771d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    void populate() {
772a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        populate(mCurItem);
773a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
774a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
775a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    void populate(int newCurrentItem) {
776a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ItemInfo oldCurInfo = null;
777a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mCurItem != newCurrentItem) {
778a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            oldCurInfo = infoForPosition(mCurItem);
779a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            mCurItem = newCurrentItem;
780a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
781a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter == null) {
783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
784d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Bail now if we are waiting to populate.  This is to hold off
787d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // on creating views from the time the user releases their finger to
788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // fling to a new position until we have finished the scroll to
789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // that position, avoiding glitches from happening at that point.
790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mPopulatePending) {
7913661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
795ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // Also, don't populate until we are attached to a window.  This is to
796ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // avoid trying to populate before we have restored our view hierarchy
797ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        // state and conflicting with what is restored.
798ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        if (getWindowToken() == null) {
799ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            return;
800ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        }
801ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn
8025c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mAdapter.startUpdate(this);
803d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
80429a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int pageLimit = mOffscreenPageLimit;
80529a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int startPos = Math.max(0, mCurItem - pageLimit);
8064c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        final int N = mAdapter.getCount();
80729a6184d74279156a9297dc67398712fb047fdc0Adam Powell        final int endPos = Math.min(N-1, mCurItem + pageLimit);
808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
809a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Locate the currently focused item or add it if needed.
810a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int curIndex = -1;
811a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        ItemInfo curItem = null;
812a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
813a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(curIndex);
814a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position >= mCurItem) {
815a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (ii.position == mCurItem) curItem = ii;
816a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                break;
817a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
818a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
819d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
820a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (curItem == null && N > 0) {
821a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            curItem = addNewItem(mCurItem, curIndex);
822a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
823a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
824a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Fill 3x the available width or up to the number of offscreen
825a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // pages requested to either side, whichever is larger.
826a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // If we have no current item we have no work to do.
827a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (curItem != null) {
828a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float extraWidthLeft = 0.f;
829a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int itemIndex = curIndex - 1;
830a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
83131bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            final float leftWidthNeeded = 2.f - curItem.widthFactor;
832a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int pos = mCurItem - 1; pos >= 0; pos--) {
83331bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
834a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (ii == null) {
835a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        break;
836a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
837a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (pos == ii.position && !ii.scrolling) {
838a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        mItems.remove(itemIndex);
839a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        mAdapter.destroyItem(this, pos, ii.object);
840a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex--;
841a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        curIndex--;
842a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
843a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
844a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else if (ii != null && pos == ii.position) {
845a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    extraWidthLeft += ii.widthFactor;
846a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    itemIndex--;
847a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
848a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else {
849a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = addNewItem(pos, itemIndex + 1);
850a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    extraWidthLeft += ii.widthFactor;
851a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    curIndex++;
852a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
8534c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                }
854d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
855d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float extraWidthRight = curItem.widthFactor;
857a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            itemIndex = curIndex + 1;
858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (extraWidthRight < 2.f) {
859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
860a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = mCurItem + 1; pos < N; pos++) {
861a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (extraWidthRight >= 2.f && pos > endPos) {
862a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (ii == null) {
863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            break;
864a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (pos == ii.position && !ii.scrolling) {
866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            mItems.remove(itemIndex);
867a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            mAdapter.destroyItem(this, pos, ii.object);
868a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
869a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
870a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    } else if (ii != null && pos == ii.position) {
871a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        extraWidthRight += ii.widthFactor;
872a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
873a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    } else {
875a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = addNewItem(pos, itemIndex);
876a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
877a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        extraWidthRight += ii.widthFactor;
878a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
879a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
880a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
881d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
882a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
883a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            calculatePageOffsets(curItem, curIndex, oldCurInfo);
884d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
885d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
8864c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        if (DEBUG) {
8874c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            Log.i(TAG, "Current page list:");
8884c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            for (int i=0; i<mItems.size(); i++) {
8894c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);
890d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
891d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
892d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
8932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
8942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
8955c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        mAdapter.finishUpdate(this);
8962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Check width measurement of current pages. Update LayoutParams as needed.
898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int childCount = getChildCount();
899a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < childCount; i++) {
900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final View child = getChildAt(i);
901a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
902a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (!lp.isDecor && lp.widthFactor == 0.f) {
903a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                // 0 means requery the adapter for this, it doesn't have a valid width.
904a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final ItemInfo ii = infoForChild(child);
905a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (ii != null) {
906a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    lp.widthFactor = ii.widthFactor;
907a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
908a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
909a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
910a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
9112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (hasFocus()) {
9122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            View currentFocused = findFocus();
913218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
9142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (ii == null || ii.position != mCurItem) {
9152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                for (int i=0; i<getChildCount(); i++) {
9162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    View child = getChildAt(i);
9172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    ii = infoForChild(child);
9182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (ii != null && ii.position == mCurItem) {
9192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        if (child.requestFocus(FOCUS_FORWARD)) {
9202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                            break;
9212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        }
9222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
9232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
9242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
9252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
926d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
927d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
928a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) {
929a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int N = mAdapter.getCount();
930a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int width = getWidth();
931a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
932a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Fix up offsets for later layout.
933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (oldCurInfo != null) {
934a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int oldCurPosition = oldCurInfo.position;
935a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Base offsets off of oldCurInfo.
936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (oldCurPosition < curItem.position) {
937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                int itemIndex = 0;
938a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii = null;
9396bd60735de55d6621a4dffb0f6f4494decda484aAdam Powell                float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset;
940a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = oldCurPosition + 1;
941a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos <= curItem.position && itemIndex < mItems.size(); pos++) {
942a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(itemIndex);
943a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos > ii.position && itemIndex < mItems.size() - 1) {
944a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex++;
945a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = mItems.get(itemIndex);
946a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos < ii.position) {
948a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // We don't have an item populated for this,
949a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // ask the adapter for an offset.
950a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        offset += mAdapter.getPageWidth(pos) + marginOffset;
951a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos++;
952a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
953a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii.offset = offset;
954a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset += ii.widthFactor + marginOffset;
955a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
956a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            } else if (oldCurPosition > curItem.position) {
957a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                int itemIndex = mItems.size() - 1;
958a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii = null;
959a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                float offset = oldCurInfo.offset;
960a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                for (int pos = oldCurPosition - 1;
961a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos >= curItem.position && itemIndex >= 0; pos--) {
962a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(itemIndex);
963a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos < ii.position && itemIndex > 0) {
964a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        itemIndex--;
965a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        ii = mItems.get(itemIndex);
966a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
967a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    while (pos > ii.position) {
968a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // We don't have an item populated for this,
969a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // ask the adapter for an offset.
970a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        offset -= mAdapter.getPageWidth(pos) + marginOffset;
971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        pos--;
972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset -= ii.widthFactor + marginOffset;
974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii.offset = offset;
975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Base all offsets off of curItem.
980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int itemCount = mItems.size();
981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float offset = curItem.offset;
982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int pos = curItem.position - 1;
983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE;
98431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell        mLastOffset = curItem.position == N - 1 ?
98531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE;
986a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Previous pages
987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = curIndex - 1; i >= 0; i--, pos--) {
988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(i);
989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            while (pos > ii.position) {
990a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                offset -= mAdapter.getPageWidth(pos--) + marginOffset;
991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
992a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset -= ii.widthFactor + marginOffset;
993a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ii.offset = offset;
994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position == 0) mFirstOffset = offset;
995a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
996a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        offset = curItem.offset + curItem.widthFactor + marginOffset;
997a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        pos = curItem.position + 1;
998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Next pages
999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = curIndex + 1; i < itemCount; i++, pos++) {
1000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = mItems.get(i);
1001a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            while (pos < ii.position) {
1002a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                offset += mAdapter.getPageWidth(pos++) + marginOffset;
1003a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
100431bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            if (ii.position == N - 1) {
100531bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                mLastOffset = offset + ii.widthFactor - 1;
100631bb17f88734747206586eeb3eb57123e3cc2434Adam Powell            }
1007a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ii.offset = offset;
1008a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset += ii.widthFactor + marginOffset;
1009a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1010a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1011a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        mNeedCalculatePageOffsets = false;
1012a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
1013a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
10147dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn    /**
10157dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * This is the persistent state that is saved by ViewPager.  Only needed
10167dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * if you are creating a sublass of ViewPager that must save its own
10177dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * state, in which case it should implement a subclass of this which
10187dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * contains that state.
10197dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     */
1020d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public static class SavedState extends BaseSavedState {
1021d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        int position;
1022ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        Parcelable adapterState;
10235c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        ClassLoader loader;
1024d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
10255c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        public SavedState(Parcelable superState) {
1026d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super(superState);
1027d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1028d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1029d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        @Override
1030d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        public void writeToParcel(Parcel out, int flags) {
1031d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.writeToParcel(out, flags);
1032d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            out.writeInt(position);
10335c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            out.writeParcelable(adapterState, flags);
1034d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1035d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1036d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        @Override
1037d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        public String toString() {
1038d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return "FragmentPager.SavedState{"
1039d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    + Integer.toHexString(System.identityHashCode(this))
1040d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    + " position=" + position + "}";
1041d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1042d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
10435c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        public static final Parcelable.Creator<SavedState> CREATOR
10445c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
10455c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    @Override
10465c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
10475c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        return new SavedState(in, loader);
10485c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    }
10495c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    @Override
10505c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    public SavedState[] newArray(int size) {
10515c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                        return new SavedState[size];
10525c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                    }
10535c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                });
10545c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn
10555c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn        SavedState(Parcel in, ClassLoader loader) {
1056d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super(in);
10575c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            if (loader == null) {
10585c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn                loader = getClass().getClassLoader();
1059ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            }
10605c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            position = in.readInt();
10615c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            adapterState = in.readParcelable(loader);
10625c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            this.loader = loader;
1063d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1064d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1065d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1066d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1067d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public Parcelable onSaveInstanceState() {
1068d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        Parcelable superState = super.onSaveInstanceState();
1069d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        SavedState ss = new SavedState(superState);
1070d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        ss.position = mCurItem;
1071677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki        if (mAdapter != null) {
1072677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki            ss.adapterState = mAdapter.saveState();
1073677ada6ea45f3889fb5118e85a3aa706f99e4d72Makoto Onuki        }
1074d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return ss;
1075d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1076d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1077d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1078d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void onRestoreInstanceState(Parcelable state) {
1079d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (!(state instanceof SavedState)) {
1080d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.onRestoreInstanceState(state);
1081d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return;
1082d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1083d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1084d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        SavedState ss = (SavedState)state;
1085d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super.onRestoreInstanceState(ss.getSuperState());
1086d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1087d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mAdapter != null) {
10885c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mAdapter.restoreState(ss.adapterState, ss.loader);
1089d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            setCurrentItemInternal(ss.position, false, true);
1090d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
1091d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mRestoredCurItem = ss.position;
1092ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            mRestoredAdapterState = ss.adapterState;
10935c1637087453de15e31861f073eae5133c4e9f7bDianne Hackborn            mRestoredClassLoader = ss.loader;
1094d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1095d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1096d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1097d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
10988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public void addView(View child, int index, ViewGroup.LayoutParams params) {
10991ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        if (!checkLayoutParams(params)) {
11001ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell            params = generateLayoutParams(params);
11011ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        }
11021ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        final LayoutParams lp = (LayoutParams) params;
11031ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        lp.isDecor |= child instanceof Decor;
1104d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mInLayout) {
11058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (lp != null && lp.isDecor) {
11068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                throw new IllegalStateException("Cannot add pager decor view during layout");
11078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
1108a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lp.needsMeasure = true;
1109d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            addViewInLayout(child, index, params);
1110d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        } else {
1111d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            super.addView(child, index, params);
1112d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1113d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1114d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (USE_CACHE) {
1115d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (child.getVisibility() != GONE) {
1116d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                child.setDrawingCacheEnabled(mScrollingCacheEnabled);
1117d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            } else {
1118d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                child.setDrawingCacheEnabled(false);
1119d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1120d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1121d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1122d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1123d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    ItemInfo infoForChild(View child) {
1124d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i=0; i<mItems.size(); i++) {
1125d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            ItemInfo ii = mItems.get(i);
1126ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn            if (mAdapter.isViewFromObject(child, ii.object)) {
1127d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return ii;
1128d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1129d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1130d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return null;
1131d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1132d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1133218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn    ItemInfo infoForAnyChild(View child) {
1134218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        ViewParent parent;
1135218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        while ((parent=child.getParent()) != this) {
1136218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            if (parent == null || !(parent instanceof View)) {
1137218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn                return null;
1138218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            }
1139218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn            child = (View)parent;
1140218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        }
1141218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        return infoForChild(child);
1142218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn    }
1143218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn
1144a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    ItemInfo infoForPosition(int position) {
1145a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < mItems.size(); i++) {
1146a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(i);
1147a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (ii.position == position) {
1148a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                return ii;
1149a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1150a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1151a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        return null;
1152a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
1153a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1155ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    protected void onAttachedToWindow() {
1156ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn        super.onAttachedToWindow();
115797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mFirstLayout = true;
1158ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    }
1159ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn
1160ea2c91b0198855073983b4a8437aa71cbd83872fDianne Hackborn    @Override
1161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // For simple implementation, or internal size is always 0.
1163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // We depend on the container to specify the layout size of
1164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // our view.  We can't really know what it is since we will be
1165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // adding and removing different arbitrary views and do not
1166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // want the layout to change as this happens.
1167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
1168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                getDefaultSize(0, heightMeasureSpec));
1169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
11708f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        final int measuredWidth = getMeasuredWidth();
11718f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        final int maxGutterSize = measuredWidth / 10;
11728f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);
11738f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell
1174d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Children are just made to fill our space.
11758f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
11768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
11778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
11788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        /*
11798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * Make sure all children have been properly measured. Decor views first.
11808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * Right now we cheat and make this less complicated by assuming decor
11818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * views won't intersect. We will pin to edges based on gravity.
11828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         */
1183862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell        int size = getChildCount();
11848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        for (int i = 0; i < size; ++i) {
11858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final View child = getChildAt(i);
11868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (child.getVisibility() != GONE) {
11878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
11888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp != null && lp.isDecor) {
11898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
11908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
11918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    int widthMode = MeasureSpec.AT_MOST;
11928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    int heightMode = MeasureSpec.AT_MOST;
11938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
11948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
11958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
11968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (consumeVertical) {
11978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        widthMode = MeasureSpec.EXACTLY;
11988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    } else if (consumeHorizontal) {
11998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        heightMode = MeasureSpec.EXACTLY;
12008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
12018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
1202a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int widthSize = childWidthSize;
1203a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int heightSize = childHeightSize;
1204a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.width != LayoutParams.WRAP_CONTENT) {
1205a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        widthMode = MeasureSpec.EXACTLY;
1206a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (lp.width != LayoutParams.FILL_PARENT) {
1207a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            widthSize = lp.width;
1208a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
1209a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1210a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.height != LayoutParams.WRAP_CONTENT) {
1211a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        heightMode = MeasureSpec.EXACTLY;
1212a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        if (lp.height != LayoutParams.FILL_PARENT) {
1213a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            heightSize = lp.height;
1214a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        }
1215a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
1216a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
1217a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
12188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    child.measure(widthSpec, heightSpec);
12198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
12208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (consumeVertical) {
12218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childHeightSize -= child.getMeasuredHeight();
12228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    } else if (consumeHorizontal) {
12238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childWidthSize -= child.getMeasuredWidth();
12248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
12258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
12268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
12278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
12288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
12298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
12308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
1231d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1232d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Make sure we have created all fragments that we need to have shown.
1233d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = true;
1234d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        populate();
1235d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = false;
1236d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
12378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        // Page views next.
1238862ffa0efd58922b8ec119bf6fa6695c316423f7Adam Powell        size = getChildCount();
1239d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i = 0; i < size; ++i) {
1240d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            final View child = getChildAt(i);
1241d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (child.getVisibility() != GONE) {
1242d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child
12438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        + ": " + mChildWidthMeasureSpec);
12448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
12458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
12468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp == null || !lp.isDecor) {
1247a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int widthSpec = MeasureSpec.makeMeasureSpec(
1248a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                            (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
1249a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    child.measure(widthSpec, mChildHeightMeasureSpec);
12508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
1251d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1252d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1253d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1254d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1255d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1256d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1257d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        super.onSizeChanged(w, h, oldw, oldh);
1258d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1259d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Make sure scroll position is set correctly.
1260053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell        if (w != oldw) {
1261329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);
1262329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
1263329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
1264329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
1265329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) {
126691eec7fd0b6ffdbb44cd13777950552f74f654e6Adam Powell        if (oldWidth > 0 && !mItems.isEmpty()) {
12678d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final int widthWithMargin = width + margin;
12685f6568e7e269783e2668527461878cadfbe65215Adam Powell            final int oldWidthWithMargin = oldWidth + oldMargin;
12698d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final int xpos = getScrollX();
12705f6568e7e269783e2668527461878cadfbe65215Adam Powell            final float pageOffset = (float) xpos / oldWidthWithMargin;
12715f6568e7e269783e2668527461878cadfbe65215Adam Powell            final int newOffsetPixels = (int) (pageOffset * widthWithMargin);
1272a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
12735f6568e7e269783e2668527461878cadfbe65215Adam Powell            scrollTo(newOffsetPixels, getScrollY());
1274329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            if (!mScroller.isFinished()) {
1275329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell                // We now return to your regularly scheduled scroll, already in progress.
1276329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell                final int newDuration = mScroller.getDuration() - mScroller.timePassed();
1277a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo targetInfo = infoForPosition(mCurItem);
12785f6568e7e269783e2668527461878cadfbe65215Adam Powell                mScroller.startScroll(newOffsetPixels, 0,
12798d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                        (int) (targetInfo.offset * width), 0, newDuration);
1280329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            }
1281329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        } else {
1282a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo ii = infoForPosition(mCurItem);
12838d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0;
12848d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final int scrollPos = (int) (scrollOffset * width);
1285329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            if (scrollPos != getScrollX()) {
1286329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell                completeScroll();
1287053e500a0e25cabf53139f57dc474a0b28751b91Adam Powell                scrollTo(scrollPos, getScrollY());
12889bc74aa50cd69dbd1d813102718c8dbf94c42abaAdam Powell            }
1289d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1290d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1291d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1292d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1293d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    protected void onLayout(boolean changed, int l, int t, int r, int b) {
1294d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = true;
1295d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        populate();
1296d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mInLayout = false;
1297d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1298d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int count = getChildCount();
12998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int width = r - l;
13008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int height = b - t;
13018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingLeft = getPaddingLeft();
13028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingTop = getPaddingTop();
13038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingRight = getPaddingRight();
13048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int paddingBottom = getPaddingBottom();
13058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        final int scrollX = getScrollX();
13068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
13078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        int decorCount = 0;
1308d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1309a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // First pass - decor views. We need to do this in two passes so that
1310a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // we have the proper offsets for non-decor views later.
1311d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        for (int i = 0; i < count; i++) {
13128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final View child = getChildAt(i);
13138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            if (child.getVisibility() != GONE) {
13148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
13158fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childLeft = 0;
13168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childTop = 0;
13178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (lp.isDecor) {
13188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
13198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
13208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    switch (hgrav) {
13218fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        default:
13228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = paddingLeft;
13238fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13248fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.LEFT:
13258fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = paddingLeft;
13268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingLeft += child.getMeasuredWidth();
13278fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13288fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.CENTER_HORIZONTAL:
13298fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
13308fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                    paddingLeft);
13318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.RIGHT:
13338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childLeft = width - paddingRight - child.getMeasuredWidth();
13348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingRight += child.getMeasuredWidth();
13358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
13378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    switch (vgrav) {
13388fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        default:
13398fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = paddingTop;
13408fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13418fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.TOP:
13428fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = paddingTop;
13438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingTop += child.getMeasuredHeight();
13448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13458fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.CENTER_VERTICAL:
13468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = Math.max((height - child.getMeasuredHeight()) / 2,
13478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                    paddingTop);
13488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        case Gravity.BOTTOM:
13508fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            childTop = height - paddingBottom - child.getMeasuredHeight();
13518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            paddingBottom += child.getMeasuredHeight();
13528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            break;
13538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    }
13548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    childLeft += scrollX;
1355abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                    child.layout(childLeft, childTop,
1356abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childLeft + child.getMeasuredWidth(),
1357abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childTop + child.getMeasuredHeight());
1358a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    decorCount++;
1359a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1360a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1361a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1362a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1363a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Page views. Do this once we have the right padding offsets from above.
1364a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < count; i++) {
1365a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final View child = getChildAt(i);
1366a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (child.getVisibility() != GONE) {
1367a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1368a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ItemInfo ii;
1369a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (!lp.isDecor && (ii = infoForChild(child)) != null) {
1370a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int loff = (int) (width * ii.offset);
1371a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int childLeft = paddingLeft + loff;
1372a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    int childTop = paddingTop;
1373a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    if (lp.needsMeasure) {
1374a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // This was added during layout and needs measurement.
1375a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        // Do it now that we know what we're working with.
1376a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        lp.needsMeasure = false;
1377a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        final int widthSpec = MeasureSpec.makeMeasureSpec(
1378a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                (int) ((width - paddingLeft - paddingRight) * lp.widthFactor),
1379a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                MeasureSpec.EXACTLY);
1380a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        final int heightSpec = MeasureSpec.makeMeasureSpec(
1381a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                (int) (height - paddingTop - paddingBottom),
1382a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                                MeasureSpec.EXACTLY);
1383a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                        child.measure(widthSpec, heightSpec);
1384a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    }
13858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object
13868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth()
13878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                            + "x" + child.getMeasuredHeight());
1388abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                    child.layout(childLeft, childTop,
1389abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childLeft + child.getMeasuredWidth(),
1390abc968f1eba800c34a4008deb43b015da5d23a5fAdam Powell                            childTop + child.getMeasuredHeight());
13918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
1392d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1393d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
13948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mTopPageBounds = paddingTop;
13958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mBottomPageBounds = height - paddingBottom;
13968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mDecorChildCount = decorCount;
139797d6e631c6a0f698ae6fb249617f1596cb9c1cf1Adam Powell        mFirstLayout = false;
1398d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1399d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1400d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1401d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public void computeScroll() {
1402a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
1403a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int oldX = getScrollX();
1404a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int oldY = getScrollY();
1405a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int x = mScroller.getCurrX();
1406a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int y = mScroller.getCurrY();
14073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
1408a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (oldX != x || oldY != y) {
1409a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                scrollTo(x, y);
14104783095cc69fa85e484132337526c94d42d41c43Adam Powell                if (!pageScrolled(x)) {
14114783095cc69fa85e484132337526c94d42d41c43Adam Powell                    mScroller.abortAnimation();
14124783095cc69fa85e484132337526c94d42d41c43Adam Powell                    scrollTo(0, y);
14134783095cc69fa85e484132337526c94d42d41c43Adam Powell                }
1414d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1415a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1416a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Keep on drawing until the animation has finished.
1417b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
1418a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            return;
1419d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
14204c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn
14214c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        // Done with scroll, clean up state.
142247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell        completeScroll();
1423d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1424d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
14254783095cc69fa85e484132337526c94d42d41c43Adam Powell    private boolean pageScrolled(int xpos) {
14264783095cc69fa85e484132337526c94d42d41c43Adam Powell        if (mItems.size() == 0) {
14274783095cc69fa85e484132337526c94d42d41c43Adam Powell            mCalledSuper = false;
14284783095cc69fa85e484132337526c94d42d41c43Adam Powell            onPageScrolled(0, 0, 0);
14294783095cc69fa85e484132337526c94d42d41c43Adam Powell            if (!mCalledSuper) {
14304783095cc69fa85e484132337526c94d42d41c43Adam Powell                throw new IllegalStateException(
14314783095cc69fa85e484132337526c94d42d41c43Adam Powell                        "onPageScrolled did not call superclass implementation");
14324783095cc69fa85e484132337526c94d42d41c43Adam Powell            }
14334783095cc69fa85e484132337526c94d42d41c43Adam Powell            return false;
14344783095cc69fa85e484132337526c94d42d41c43Adam Powell        }
1435a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo ii = infoForCurrentScrollPosition();
1436a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int width = getWidth();
1437a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int widthWithMargin = width + mPageMargin;
1438a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = (float) mPageMargin / width;
1439a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int currentPage = ii.position;
1440a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float pageOffset = (((float) xpos / width) - ii.offset) /
1441a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                (ii.widthFactor + marginOffset);
1442a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int offsetPixels = (int) (pageOffset * widthWithMargin);
14438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCalledSuper = false;
1445a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        onPageScrolled(currentPage, pageOffset, offsetPixels);
14468fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (!mCalledSuper) {
14478fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            throw new IllegalStateException(
14488fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    "onPageScrolled did not call superclass implementation");
14498fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
14504783095cc69fa85e484132337526c94d42d41c43Adam Powell        return true;
14518fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
14528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    /**
14548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * This method will be invoked when the current page is scrolled, either as part
14558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
14568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * If you override this method you must call through to the superclass implementation
14578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled
14588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * returns.
14598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *
14608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param position Position index of the first page currently being displayed.
14618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     *                 Page position+1 will be visible if positionOffset is nonzero.
14628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param offset Value from [0, 1) indicating the offset from the page at position.
14638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     * @param offsetPixels Value in pixels indicating the offset from position.
14648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell     */
14658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected void onPageScrolled(int position, float offset, int offsetPixels) {
14668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        // Offset any decor views if needed - keep them on-screen at all times.
14678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mDecorChildCount > 0) {
14688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int scrollX = getScrollX();
14698fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            int paddingLeft = getPaddingLeft();
14708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            int paddingRight = getPaddingRight();
14718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int width = getWidth();
14728fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final int childCount = getChildCount();
14738fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            for (int i = 0; i < childCount; i++) {
14748fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final View child = getChildAt(i);
14758fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
14768fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (!lp.isDecor) continue;
14778fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14788fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
14798fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                int childLeft = 0;
14808fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                switch (hgrav) {
14818fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    default:
14828fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = paddingLeft;
14838fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
14848fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.LEFT:
14858fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = paddingLeft;
14868fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        paddingLeft += child.getWidth();
14878fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
14888fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.CENTER_HORIZONTAL:
14898fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
14908fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                                paddingLeft);
14918fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
14928fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    case Gravity.RIGHT:
14938fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        childLeft = width - paddingRight - child.getMeasuredWidth();
14948fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        paddingRight += child.getMeasuredWidth();
14958fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                        break;
14968fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
14978fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                childLeft += scrollX;
14988fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
14998fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                final int childOffset = childLeft - child.getLeft();
15008fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                if (childOffset != 0) {
15018fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                    child.offsetLeftAndRight(childOffset);
15028fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell                }
15038fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            }
15048fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
15058fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
15068fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mOnPageChangeListener != null) {
15078fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);
15088fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
15098fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        if (mInternalPageChangeListener != null) {
15108fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);
15118fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
15128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        mCalledSuper = true;
15138fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
15148fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
151547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell    private void completeScroll() {
15168d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell        boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;
1517cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham        if (needPopulate) {
15184c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            // Done with scroll, no longer want to cache view drawing.
15194c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            setScrollingCacheEnabled(false);
1520d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mScroller.abortAnimation();
1521d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int oldX = getScrollX();
1522d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int oldY = getScrollY();
1523d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int x = mScroller.getCurrX();
1524d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            int y = mScroller.getCurrY();
1525d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (oldX != x || oldY != y) {
1526d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                scrollTo(x, y);
1527d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
152847dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell            setScrollState(SCROLL_STATE_IDLE);
15294c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
15303661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        mPopulatePending = false;
15314c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        for (int i=0; i<mItems.size(); i++) {
15324c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            ItemInfo ii = mItems.get(i);
15334c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            if (ii.scrolling) {
15344c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                needPopulate = true;
15354c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn                ii.scrolling = false;
15364c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            }
15374c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        }
15384c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn        if (needPopulate) {
15394c2eb6dc16814bc44915d7603d1af465dff0407dDianne Hackborn            populate();
1540d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1541d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1542d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
15438f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    private boolean isGutterDrag(float x, float dx) {
15448f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell        return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0);
15458f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell    }
15468f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell
1547d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1548d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public boolean onInterceptTouchEvent(MotionEvent ev) {
1549d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        /*
1550d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * This method JUST determines whether we want to intercept the motion.
1551d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * If we return true, onMotionEvent will be called and we do the actual
1552d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         * scrolling there.
1553d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn         */
1554d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1555d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
1556d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1557d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Always take care of the touch gesture being complete.
1558d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
1559d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Release the drag.
1560d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (DEBUG) Log.v(TAG, "Intercept done!");
1561d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mIsBeingDragged = false;
1562d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mIsUnableToDrag = false;
1563d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mActivePointerId = INVALID_POINTER;
15643ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            if (mVelocityTracker != null) {
15653ce9274ccb8034c1787415c77307bbda36071bddAdam Powell                mVelocityTracker.recycle();
15663ce9274ccb8034c1787415c77307bbda36071bddAdam Powell                mVelocityTracker = null;
15673ce9274ccb8034c1787415c77307bbda36071bddAdam Powell            }
1568d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return false;
1569d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1570d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1571d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // Nothing more to do here if we have decided whether or not we
1572d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        // are dragging.
1573d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (action != MotionEvent.ACTION_DOWN) {
1574d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mIsBeingDragged) {
1575d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Intercept returning true!");
1576d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return true;
1577d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1578d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mIsUnableToDrag) {
1579d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Intercept returning false!");
1580d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                return false;
1581d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1582d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1583d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1584d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        switch (action) {
1585d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_MOVE: {
1586d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1587d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
1588d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * whether the user has moved far enough from his original down touch.
1589d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 */
1590d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1591d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1592d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                * Locally do absolute value. mLastMotionY is set to the y value
1593d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                * of the down event.
1594d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                */
1595d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int activePointerId = mActivePointerId;
1596d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (activePointerId == INVALID_POINTER) {
1597d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    // If we don't have a valid id, the touch down wasn't on content.
1598d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    break;
1599d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1600d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1601d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
1602d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float x = MotionEventCompat.getX(ev, pointerIndex);
160347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                final float dx = x - mLastMotionX;
160447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                final float xDiff = Math.abs(dx);
1605d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float y = MotionEventCompat.getY(ev, pointerIndex);
160647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                final float yDiff = Math.abs(y - mLastMotionY);
1607d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
1608bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
16098f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell                if (dx != 0 && !isGutterDrag(mLastMotionX, dx) &&
16108f19b17dbc34bfc7e5caacbf83a7099e5cb5a47cAdam Powell                        canScroll(this, false, (int) dx, (int) x, (int) y)) {
1611bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    // Nested view has scrollable area under this point. Let it be handled there.
1612bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    mInitialMotionX = mLastMotionX = x;
1613bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    mLastMotionY = y;
1614b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                    mIsUnableToDrag = true;
1615bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    return false;
1616bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                }
1617d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (xDiff > mTouchSlop && xDiff > yDiff) {
1618d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    if (DEBUG) Log.v(TAG, "Starting drag!");
1619d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mIsBeingDragged = true;
162047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    setScrollState(SCROLL_STATE_DRAGGING);
16218d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                    mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop :
16228d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                            mInitialMotionX - mTouchSlop;
1623d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    setScrollingCacheEnabled(true);
1624d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                } else {
1625d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    if (yDiff > mTouchSlop) {
1626d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        // The finger has moved enough in the vertical
1627d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        // direction to be counted as a drag...  abort
1628d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        // any attempt to drag horizontally, to work correctly
1629d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        // with children that have scrolling containers.
1630d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        if (DEBUG) Log.v(TAG, "Starting unable to drag!");
1631d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        mIsUnableToDrag = true;
1632d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    }
1633d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
16346e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                if (mIsBeingDragged) {
16356e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                    // Scroll to follow the motion event
16366e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                    if (performDrag(x)) {
16376e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                        ViewCompat.postInvalidateOnAnimation(this);
16386e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                    }
16396e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                }
1640d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1641d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1642d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1643d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_DOWN: {
1644d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                /*
1645d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * Remember location of down touch.
1646d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 * ACTION_DOWN always refers to pointer index 0.
1647d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                 */
1648d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = mInitialMotionX = ev.getX();
1649d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionY = ev.getY();
1650d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
1651b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                mIsUnableToDrag = false;
1652d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
16538d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                mScroller.computeScrollOffset();
1654b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                if (mScrollState == SCROLL_STATE_SETTLING &&
1655b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell                        Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
165647dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    // Let the user 'catch' the pager as it animates.
16578d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                    mScroller.abortAnimation();
16588d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                    mPopulatePending = false;
16598d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                    populate();
166047dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    mIsBeingDragged = true;
166147dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    setScrollState(SCROLL_STATE_DRAGGING);
166247dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                } else {
166347dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    completeScroll();
166447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    mIsBeingDragged = false;
166547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                }
1666d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1667d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
1668d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        + " mIsBeingDragged=" + mIsBeingDragged
1669d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        + "mIsUnableToDrag=" + mIsUnableToDrag);
1670d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1671d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1672d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1673d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_UP:
1674d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                onSecondaryPointerUp(ev);
1675d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1676d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1677d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
16788d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell        if (mVelocityTracker == null) {
16798d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            mVelocityTracker = VelocityTracker.obtain();
16803ce9274ccb8034c1787415c77307bbda36071bddAdam Powell        }
16818d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell        mVelocityTracker.addMovement(ev);
16823ce9274ccb8034c1787415c77307bbda36071bddAdam Powell
1683d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        /*
16843ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         * The only time we want to intercept motion events is if we are in the
16853ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         * drag mode.
16863ce9274ccb8034c1787415c77307bbda36071bddAdam Powell         */
1687d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return mIsBeingDragged;
1688d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1689d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1690d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    @Override
1691d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    public boolean onTouchEvent(MotionEvent ev) {
169269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mFakeDragging) {
169369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // A fake drag is in progress already, ignore this real one
169469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // but still eat the touch events.
169569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            // (It is likely that the user is multi-touching the screen.)
169669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            return true;
169769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
1698d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1699d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
1700d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // Don't handle edge touches immediately -- they may actually belong to one of our
1701d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // descendants.
1702d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            return false;
1703d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1704d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
17053661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        if (mAdapter == null || mAdapter.getCount() == 0) {
17063661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            // Nothing to present or scroll; nothing to touch.
17073661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            return false;
17083661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
17093661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
1710d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mVelocityTracker == null) {
1711d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker = VelocityTracker.obtain();
1712d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1713d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mVelocityTracker.addMovement(ev);
1714d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1715d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int action = ev.getAction();
1716560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        boolean needsInvalidate = false;
1717d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1718d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        switch (action & MotionEventCompat.ACTION_MASK) {
1719d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_DOWN: {
17208d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                mScroller.abortAnimation();
17218d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                mPopulatePending = false;
17228d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                populate();
17238d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                mIsBeingDragged = true;
17248d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                setScrollState(SCROLL_STATE_DRAGGING);
1725d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1726d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                // Remember where the motion event started
1727d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = mInitialMotionX = ev.getX();
1728d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
1729d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1730d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1731d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_MOVE:
17323661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                if (!mIsBeingDragged) {
17333661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
17343661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final float x = MotionEventCompat.getX(ev, pointerIndex);
173547dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    final float xDiff = Math.abs(x - mLastMotionX);
17363661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    final float y = MotionEventCompat.getY(ev, pointerIndex);
173747dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                    final float yDiff = Math.abs(y - mLastMotionY);
17383661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
17393661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    if (xDiff > mTouchSlop && xDiff > yDiff) {
17403661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        if (DEBUG) Log.v(TAG, "Starting drag!");
17413661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        mIsBeingDragged = true;
17428d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                        mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
17438d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell                                mInitialMotionX - mTouchSlop;
174447dc57337c13a2760ea3512ad84d6aa9f24ccd28Adam Powell                        setScrollState(SCROLL_STATE_DRAGGING);
17453661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                        setScrollingCacheEnabled(true);
17463661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                    }
17473661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell                }
174831bb17f88734747206586eeb3eb57123e3cc2434Adam Powell                // Not else! Note that mIsBeingDragged can be set above.
1749d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
1750d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    // Scroll to follow the motion event
1751d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final int activePointerIndex = MotionEventCompat.findPointerIndex(
1752d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                            ev, mActivePointerId);
1753d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final float x = MotionEventCompat.getX(ev, activePointerIndex);
17546e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                    needsInvalidate |= performDrag(x);
1755d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1756d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1757d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_UP:
1758d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
1759d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final VelocityTracker velocityTracker = mVelocityTracker;
1760d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
17611cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
1762d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                            velocityTracker, mActivePointerId);
1763d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mPopulatePending = true;
1764a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int width = getWidth();
17651cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    final int scrollX = getScrollX();
1766a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final ItemInfo ii = infoForCurrentScrollPosition();
1767a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final int currentPage = ii.position;
1768a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
1769035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final int activePointerIndex =
1770035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                            MotionEventCompat.findPointerIndex(ev, mActivePointerId);
1771035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final float x = MotionEventCompat.getX(ev, activePointerIndex);
1772035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    final int totalDelta = (int) (x - mInitialMotionX);
1773035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                    int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
1774035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell                            totalDelta);
17751cbf48f28f6ef523af2a4aafa98c5437964cb48aAdam Powell                    setCurrentItemInternal(nextPage, true, true, initialVelocity);
1776d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
1777d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mActivePointerId = INVALID_POINTER;
1778d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    endDrag();
1779560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
1780d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1781d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1782d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEvent.ACTION_CANCEL:
1783d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                if (mIsBeingDragged) {
1784d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    setCurrentItemInternal(mCurItem, true, true);
1785d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    mActivePointerId = INVALID_POINTER;
1786d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    endDrag();
1787560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
1788d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
1789d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1790d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_DOWN: {
1791d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int index = MotionEventCompat.getActionIndex(ev);
1792d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final float x = MotionEventCompat.getX(ev, index);
1793d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = x;
1794d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mActivePointerId = MotionEventCompat.getPointerId(ev, index);
1795d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1796d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
1797d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            case MotionEventCompat.ACTION_POINTER_UP:
1798d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                onSecondaryPointerUp(ev);
1799d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mLastMotionX = MotionEventCompat.getX(ev,
1800d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        MotionEventCompat.findPointerIndex(ev, mActivePointerId));
1801d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                break;
1802d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
1803560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (needsInvalidate) {
1804b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
1805560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
1806d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        return true;
1807d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
1808d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
18096e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell    private boolean performDrag(float x) {
18106e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        boolean needsInvalidate = false;
18116e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
18126e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        final float deltaX = mLastMotionX - x;
18136e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        mLastMotionX = x;
18146e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
18156e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        float oldScrollX = getScrollX();
18166e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        float scrollX = oldScrollX + deltaX;
18176e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        final int width = getWidth();
18186e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
18196e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        float leftBound = width * mFirstOffset;
18206e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        float rightBound = width * mLastOffset;
18216e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        boolean leftAbsolute = true;
18226e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        boolean rightAbsolute = true;
18236e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
18246e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        final ItemInfo firstItem = mItems.get(0);
18256e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
18266e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        if (firstItem.position != 0) {
18276e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            leftAbsolute = false;
18286e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            leftBound = firstItem.offset * width;
18296e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        }
18306e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        if (lastItem.position != mAdapter.getCount() - 1) {
18316e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            rightAbsolute = false;
18326e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            rightBound = lastItem.offset * width;
18336e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        }
18346e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
18356e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        if (scrollX < leftBound) {
18366e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            if (leftAbsolute) {
18376e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                float over = leftBound - scrollX;
18386e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width);
18396e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            }
18406e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            scrollX = leftBound;
18416e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        } else if (scrollX > rightBound) {
18426e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            if (rightAbsolute) {
18436e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                float over = scrollX - rightBound;
18446e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell                needsInvalidate = mRightEdge.onPull(Math.abs(over) / width);
18456e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            }
18466e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell            scrollX = rightBound;
18476e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        }
18486e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        // Don't lose the rounded component
18496e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        mLastMotionX += scrollX - (int) scrollX;
18506e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        scrollTo((int) scrollX, getScrollY());
18516e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        pageScrolled((int) scrollX);
18526e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
18536e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell        return needsInvalidate;
18546e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell    }
18556e7700ca575523895f8ebc5696e3e57aeccf30c0Adam Powell
1856a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    /**
1857a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     * @return Info about the page at the current scroll position.
1858a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     *         This can be synthetic for a missing middle page; the 'object' field can be null.
1859a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell     */
1860a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    private ItemInfo infoForCurrentScrollPosition() {
1861a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int width = getWidth();
1862a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0;
1863a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
1864a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int lastPos = -1;
1865a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float lastOffset = 0.f;
1866a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float lastWidth = 0.f;
1867a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        boolean first = true;
1868a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1869ad079a869adf67a87a2721342de27970a3ba1844Adam Powell        ItemInfo lastItem = null;
1870a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        for (int i = 0; i < mItems.size(); i++) {
1871a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(i);
1872a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float offset;
1873a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            if (!first && ii.position != lastPos + 1) {
1874a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                // Create a synthetic item for a missing page.
1875a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii = mTempItem;
1876a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.offset = lastOffset + lastWidth + marginOffset;
1877a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.position = lastPos + 1;
1878a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                ii.widthFactor = mAdapter.getPageWidth(ii.position);
1879a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                i--;
1880a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1881a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            offset = ii.offset;
1882a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
18838d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final float leftBound = offset;
18848d3dd8427b57f463f0d4959c0ad8796008472caaAdam Powell            final float rightBound = offset + ii.widthFactor + marginOffset;
1885ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            if (first || scrollOffset >= leftBound) {
1886ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                if (scrollOffset < rightBound || i == mItems.size() - 1) {
1887ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                    return ii;
1888ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                }
1889ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            } else {
1890ad079a869adf67a87a2721342de27970a3ba1844Adam Powell                return lastItem;
1891a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            }
1892a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            first = false;
1893a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastPos = ii.position;
1894a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastOffset = offset;
1895a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            lastWidth = ii.widthFactor;
1896ad079a869adf67a87a2721342de27970a3ba1844Adam Powell            lastItem = ii;
1897a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1898a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1899ad079a869adf67a87a2721342de27970a3ba1844Adam Powell        return lastItem;
1900a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell    }
1901a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1902035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
1903035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        int targetPage;
1904035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
1905035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            targetPage = velocity > 0 ? currentPage : currentPage + 1;
1906035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        } else {
1907035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell            targetPage = (int) (currentPage + pageOffset + 0.5f);
1908035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        }
1909035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell
1910a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mItems.size() > 0) {
1911a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo firstItem = mItems.get(0);
1912a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final ItemInfo lastItem = mItems.get(mItems.size() - 1);
1913a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1914a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            // Only let the user target pages we have items for
1915a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
1916a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
1917a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1918035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        return targetPage;
1919035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell    }
1920035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell
1921560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    @Override
1922560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    public void draw(Canvas canvas) {
1923560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        super.draw(canvas);
1924560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        boolean needsInvalidate = false;
1925560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1926560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        final int overScrollMode = ViewCompat.getOverScrollMode(this);
1927560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
1928560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS &&
1929560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                        mAdapter != null && mAdapter.getCount() > 1)) {
1930560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            if (!mLeftEdge.isFinished()) {
1931560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int restoreCount = canvas.save();
1932560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
1933a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                final int width = getWidth();
1934560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1935560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.rotate(270);
1936a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                canvas.translate(-height + getPaddingTop(), mFirstOffset * width);
1937a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                mLeftEdge.setSize(height, width);
1938560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                needsInvalidate |= mLeftEdge.draw(canvas);
1939560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.restoreToCount(restoreCount);
1940560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            }
1941560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            if (!mRightEdge.isFinished()) {
1942560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int restoreCount = canvas.save();
1943560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int width = getWidth();
1944560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
1945560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1946560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.rotate(90);
1947a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width);
1948560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                mRightEdge.setSize(height, width);
1949560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                needsInvalidate |= mRightEdge.draw(canvas);
1950560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell                canvas.restoreToCount(restoreCount);
1951560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            }
1952560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        } else {
1953560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            mLeftEdge.finish();
1954560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            mRightEdge.finish();
1955560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
1956560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1957560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        if (needsInvalidate) {
1958560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell            // Keep animating
1959b469af6dc2f8cda4020a78fb4582c1483089fd6eAdam Powell            ViewCompat.postInvalidateOnAnimation(this);
1960560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell        }
1961560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell    }
1962560114f591be31d0fb73c26a1ee1cc0a15184abaAdam Powell
1963329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    @Override
1964329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    protected void onDraw(Canvas canvas) {
1965329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        super.onDraw(canvas);
1966329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
1967a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        // Draw the margin drawable between pages if needed.
1968a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) {
1969329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            final int scrollX = getScrollX();
1970329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            final int width = getWidth();
1971a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1972a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final float marginOffset = (float) mPageMargin / width;
1973a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            int itemIndex = 0;
1974a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            ItemInfo ii = mItems.get(0);
1975a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            float offset = ii.offset;
1976a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int itemCount = mItems.size();
1977a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int firstPos = ii.position;
1978a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            final int lastPos = mItems.get(itemCount - 1).position;
1979a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            for (int pos = firstPos; pos < lastPos; pos++) {
1980a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                while (pos > ii.position && itemIndex < itemCount) {
1981a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    ii = mItems.get(++itemIndex);
1982a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1983a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
198423b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                float drawAt;
1985a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (pos == ii.position) {
198623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                    drawAt = (ii.offset + ii.widthFactor) * width;
1987a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset = ii.offset + ii.widthFactor + marginOffset;
1988a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                } else {
1989a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    float widthFactor = mAdapter.getPageWidth(pos);
199023b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                    drawAt = (offset + widthFactor) * width;
1991a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    offset += widthFactor + marginOffset;
1992a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1993a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
1994a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (drawAt + mPageMargin > scrollX) {
1995a56d6faa9df608aaa2907864669800abb68acec7Adam Powell                    mMarginDrawable.setBounds((int) drawAt, mTopPageBounds,
199623b42ec742c2047d6bb9b364c9609e6e0af13b9dAdam Powell                            (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds);
1997a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    mMarginDrawable.draw(canvas);
1998a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
1999a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2000a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                if (drawAt > scrollX + width) {
2001a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                    break; // No more visible, no sense in continuing
2002a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                }
2003329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell            }
2004329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell        }
2005329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell    }
2006329da4d5431ae7923279b56b45b84e70c52f8eeeAdam Powell
200769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
200869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Start a fake drag of the pager.
200969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
201069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager
201169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * with the touch scrolling of another view, while still letting the ViewPager
201269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.)
201369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call
201469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * {@link #endFakeDrag()} to complete the fake drag and fling as necessary.
201569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
201669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag
201769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * is already in progress, this method will return false.
201869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
201969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @return true if the fake drag began successfully, false if it could not be started.
202069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
202169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
202269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
202369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
202469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public boolean beginFakeDrag() {
202569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mIsBeingDragged) {
202669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            return false;
202769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
202869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragging = true;
202969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        setScrollState(SCROLL_STATE_DRAGGING);
203069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mInitialMotionX = mLastMotionX = 0;
203169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (mVelocityTracker == null) {
203269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            mVelocityTracker = VelocityTracker.obtain();
203369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        } else {
203469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            mVelocityTracker.clear();
203569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
203669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final long time = SystemClock.uptimeMillis();
203769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0);
203869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mVelocityTracker.addMovement(ev);
203969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        ev.recycle();
204069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragBeginTime = time;
204169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        return true;
204269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
204369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
204469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
204569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * End a fake drag of the pager.
204669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
204769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
204869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
204969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
205069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public void endFakeDrag() {
205169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (!mFakeDragging) {
205269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
205369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
205469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
205569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final VelocityTracker velocityTracker = mVelocityTracker;
205669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
20570f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell        int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
205869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell                velocityTracker, mActivePointerId);
205969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mPopulatePending = true;
2060a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int width = getWidth();
2061035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        final int scrollX = getScrollX();
2062a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo ii = infoForCurrentScrollPosition();
2063a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int currentPage = ii.position;
2064a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
2065a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final int totalDelta = (int) (mLastMotionX - mInitialMotionX);
2066a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
2067a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell                totalDelta);
2068035f6aa81bbb439d2aa20dcd2eac4459a76d561eAdam Powell        setCurrentItemInternal(nextPage, true, true, initialVelocity);
206969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        endDrag();
207069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
207169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mFakeDragging = false;
207269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
207369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
207469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
207569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first.
207669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
207769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @param xOffset Offset in pixels to drag by.
207869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
207969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
208069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
208169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public void fakeDragBy(float xOffset) {
208269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (!mFakeDragging) {
208369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
208469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
208569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
208669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mLastMotionX += xOffset;
2087a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2088a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float oldScrollX = getScrollX();
20890f034dc2c69044597a91649b8c073ae5e98a2f25Adam Powell        float scrollX = oldScrollX - xOffset;
209069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final int width = getWidth();
209169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
2092a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float leftBound = width * mFirstOffset;
2093a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        float rightBound = width * mLastOffset;
2094a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2095a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo firstItem = mItems.get(0);
2096a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
2097a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (firstItem.position != 0) {
2098a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            leftBound = firstItem.offset * width;
2099a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
2100a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        if (lastItem.position != mAdapter.getCount() - 1) {
2101a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            rightBound = lastItem.offset * width;
2102a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        }
2103a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
210469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        if (scrollX < leftBound) {
210569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            scrollX = leftBound;
210669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        } else if (scrollX > rightBound) {
210769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell            scrollX = rightBound;
210869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        }
210969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        // Don't lose the rounded component
211069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mLastMotionX += scrollX - (int) scrollX;
211169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        scrollTo((int) scrollX, getScrollY());
21128fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        pageScrolled((int) scrollX);
211369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
211469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        // Synthesize an event for the VelocityTracker.
211569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final long time = SystemClock.uptimeMillis();
211669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE,
211769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell                mLastMotionX, 0, 0);
211869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        mVelocityTracker.addMovement(ev);
211969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        ev.recycle();
212069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
212169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
212269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    /**
212369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * Returns true if a fake drag is in progress.
212469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
212569b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @return true if currently in a fake drag, false otherwise.
212669b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     *
212769b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #beginFakeDrag()
212869b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #fakeDragBy(float)
212969b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     * @see #endFakeDrag()
213069b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell     */
213169b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    public boolean isFakeDragging() {
213269b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell        return mFakeDragging;
213369b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell    }
213469b7a33f67a5577ceb2bd43ff389d89b592f85b1Adam Powell
2135d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void onSecondaryPointerUp(MotionEvent ev) {
2136d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int pointerIndex = MotionEventCompat.getActionIndex(ev);
2137d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
2138d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (pointerId == mActivePointerId) {
2139d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // This was our active pointer going up. Choose a new
2140d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            // active pointer and adjust accordingly.
2141d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
2142d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);
2143d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
2144d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (mVelocityTracker != null) {
2145d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                mVelocityTracker.clear();
2146d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
2147d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2148d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
2149d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2150d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void endDrag() {
2151d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mIsBeingDragged = false;
2152d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        mIsUnableToDrag = false;
2153d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2154d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mVelocityTracker != null) {
2155d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker.recycle();
2156d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mVelocityTracker = null;
2157d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2158d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
2159d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn
2160d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    private void setScrollingCacheEnabled(boolean enabled) {
2161d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        if (mScrollingCacheEnabled != enabled) {
2162d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            mScrollingCacheEnabled = enabled;
2163d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            if (USE_CACHE) {
2164d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                final int size = getChildCount();
2165d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                for (int i = 0; i < size; ++i) {
2166d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    final View child = getChildAt(i);
2167d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    if (child.getVisibility() != GONE) {
2168d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                        child.setDrawingCacheEnabled(enabled);
2169d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                    }
2170d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn                }
2171d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn            }
2172d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn        }
2173d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn    }
21743661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell
2175bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell    /**
2176cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * Tests scrollability within child views of v given a delta of dx.
2177bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     *
2178bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param v View to test for horizontal scrollability
2179bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
2180bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     *               or just its children (false).
2181bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param dx Delta scrolled in pixels
2182cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @param x X coordinate of the active touch point
2183bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     * @param y Y coordinate of the active touch point
2184cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham     * @return true if child views of v can be scrolled by delta of dx.
2185bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell     */
2186cf2312ee850d26c9d1a2413c996d41397e816fb5Minh Pham    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
2187bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        if (v instanceof ViewGroup) {
2188bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final ViewGroup group = (ViewGroup) v;
2189bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int scrollX = v.getScrollX();
2190bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int scrollY = v.getScrollY();
2191bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            final int count = group.getChildCount();
2192bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            // Count backwards - let topmost views consume scroll distance first.
2193bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            for (int i = count - 1; i >= 0; i--) {
2194bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                // TODO: Add versioned support here for transformed views.
2195bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                // This will not work for transformed views in Honeycomb+
2196bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                final View child = group.getChildAt(i);
2197bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
2198bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
2199bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
2200bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                                y + scrollY - child.getTop())) {
2201bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                    return true;
2202bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell                }
2203bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell            }
2204bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        }
2205bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
2206bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell        return checkV && ViewCompat.canScrollHorizontally(v, -dx);
2207bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell    }
2208bc889e39e279fcf8c3d35fc11d8052c002eddf38Adam Powell
2209481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    @Override
22102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean dispatchKeyEvent(KeyEvent event) {
22112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // Let the focused view and/or our descendants get the key first
22122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
22132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
22142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
22162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * You can call this function yourself to have the scroll view perform
22172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * scrolling from a key event, just as if the event had been dispatched to
22182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * it by the view hierarchy.
22192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     *
22202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * @param event The key event to execute.
22212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * @return Return true if the event was handled, else false.
22222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
22232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean executeKeyEvent(KeyEvent event) {
22242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        boolean handled = false;
22252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (event.getAction() == KeyEvent.ACTION_DOWN) {
22262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            switch (event.getKeyCode()) {
22272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_DPAD_LEFT:
22282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = arrowScroll(FOCUS_LEFT);
22292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
22302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_DPAD_RIGHT:
22312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = arrowScroll(FOCUS_RIGHT);
22322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
22332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                case KeyEvent.KEYCODE_TAB:
22345de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                    if (Build.VERSION.SDK_INT >= 11) {
22355de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD
22365de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        // before Android 3.0. Ignore the tab key on those devices.
22375de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        if (KeyEventCompat.hasNoModifiers(event)) {
22385de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                            handled = arrowScroll(FOCUS_FORWARD);
22395de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {
22405de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                            handled = arrowScroll(FOCUS_BACKWARD);
22415de8804b248eebaf7c29113ec80a0dff3a03c97aAdam Powell                        }
22422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
22432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    break;
22442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
22452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return handled;
22472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
22482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public boolean arrowScroll(int direction) {
22502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        View currentFocused = findFocus();
22512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (currentFocused == this) currentFocused = null;
22522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        boolean handled = false;
22542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
22552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,
22562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                direction);
22572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (nextFocused != null && nextFocused != currentFocused) {
22582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (direction == View.FOCUS_LEFT) {
22592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // If there is nothing to the left, or this is causing us to
22602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // jump to the right, then what we really want to do is page left.
2261dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
2262dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
2263dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                if (currentFocused != null && nextLeft >= currLeft) {
22642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = pageLeft();
22652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                } else {
22662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = nextFocused.requestFocus();
22672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
22682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            } else if (direction == View.FOCUS_RIGHT) {
22692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // If there is nothing to the right, or this is causing us to
22702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // jump to the left, then what we really want to do is page right.
2271dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
2272dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
2273dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell                if (currentFocused != null && nextLeft <= currLeft) {
22742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = pageRight();
22752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                } else {
22762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    handled = nextFocused.requestFocus();
22772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
22782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
22792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {
22802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Trying to move left and nothing there; try to page.
22812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            handled = pageLeft();
22822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {
22832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Trying to move right and nothing there; try to page.
22842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            handled = pageRight();
22852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (handled) {
22872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
22882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
22892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return handled;
22902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
22912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
2292dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell    private Rect getChildRectInPagerCoordinates(Rect outRect, View child) {
2293dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        if (outRect == null) {
2294dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect = new Rect();
2295dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        }
2296efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell        if (child == null) {
2297efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell            outRect.set(0, 0, 0, 0);
2298efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell            return outRect;
2299efea2e772645ccd2d0de3e92fa8382d5444eab11Adam Powell        }
2300dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        outRect.left = child.getLeft();
2301dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        outRect.right = child.getRight();
2302dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        outRect.top = child.getTop();
2303dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        outRect.bottom = child.getBottom();
2304dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell
2305dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        ViewParent parent = child.getParent();
2306dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        while (parent instanceof ViewGroup && parent != this) {
2307dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            final ViewGroup group = (ViewGroup) parent;
2308dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect.left += group.getLeft();
2309dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect.right += group.getRight();
2310dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect.top += group.getTop();
2311dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            outRect.bottom += group.getBottom();
2312dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell
2313dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell            parent = group.getParent();
2314dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        }
2315dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell        return outRect;
2316dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell    }
2317dd24aab287e08428b20270b9f12921af13fbd72bAdam Powell
23182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    boolean pageLeft() {
23192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (mCurItem > 0) {
23202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            setCurrentItem(mCurItem-1, true);
23212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return true;
23222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
23232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
23242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
23252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23262a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    boolean pageRight() {
2327218c1e661578e2a17928f7dbb590b43d1c79aeb7Dianne Hackborn        if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) {
23282a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            setCurrentItem(mCurItem+1, true);
23292a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            return true;
23302a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
23312a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
23322a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
23332a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23342a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
23352a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be focusable.
23362a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
23372a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
23382a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
23392a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        final int focusableCount = views.size();
23402a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23412a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        final int descendantFocusability = getDescendantFocusability();
23422a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23432a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
23442a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            for (int i = 0; i < getChildCount(); i++) {
23452a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                final View child = getChildAt(i);
23462a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (child.getVisibility() == VISIBLE) {
23472a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    ItemInfo ii = infoForChild(child);
23482a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (ii != null && ii.position == mCurItem) {
23492a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        child.addFocusables(views, direction, focusableMode);
23502a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
23512a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
23522a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
23532a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
23542a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23552a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // we add ourselves (if focusable) in all cases except for when we are
23562a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
23572a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // to avoid the focus search finding layouts when a more precise search
23582a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // among the focusable children would be more interesting.
23592a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if (
23602a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
23612a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                // No focusable descendants
23622a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                (focusableCount == views.size())) {
23632a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // Note that we can't call the superclass here, because it will
23642a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            // add all views in.  So we need to do the same thing View does.
23652a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (!isFocusable()) {
23662a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return;
23672a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
23682a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE &&
23692a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    isInTouchMode() && !isFocusableInTouchMode()) {
23702a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                return;
23712a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
23722a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (views != null) {
23732a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                views.add(this);
23742a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
23752a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
23762a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
23772a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23782a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
23792a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be touchable.
23802a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
23812a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
23822a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    public void addTouchables(ArrayList<View> views) {
23832a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // Note that we don't call super.addTouchables(), which means that
23842a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // we don't call View.addTouchables().  This is okay because a ViewPager
23852a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        // is itself not touchable.
23862a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        for (int i = 0; i < getChildCount(); i++) {
23872a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            final View child = getChildAt(i);
23882a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (child.getVisibility() == VISIBLE) {
23892a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                ItemInfo ii = infoForChild(child);
23902a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (ii != null && ii.position == mCurItem) {
23912a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    child.addTouchables(views);
23922a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
23932a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
23942a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
23952a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    }
23962a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn
23972a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    /**
23982a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     * We only want the current page that is being shown to be focusable.
23992a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn     */
24002a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    @Override
24012a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn    protected boolean onRequestFocusInDescendants(int direction,
24022a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            Rect previouslyFocusedRect) {
24032a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int index;
24042a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int increment;
24052a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int end;
24062a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        int count = getChildCount();
24072a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        if ((direction & FOCUS_FORWARD) != 0) {
24082a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            index = 0;
24092a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            increment = 1;
24102a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            end = count;
24112a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        } else {
24122a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            index = count - 1;
24132a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            increment = -1;
24142a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            end = -1;
24152a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        }
24162a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        for (int i = index; i != end; i += increment) {
24172a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            View child = getChildAt(i);
24182a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            if (child.getVisibility() == VISIBLE) {
24192a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                ItemInfo ii = infoForChild(child);
24202a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                if (ii != null && ii.position == mCurItem) {
24212a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    if (child.requestFocus(direction, previouslyFocusedRect)) {
24222a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                        return true;
24232a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                    }
24242a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn                }
24252a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn            }
2426481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        }
24272a4d8518f36346ea25a22a736453ff28f2954165Dianne Hackborn        return false;
2428481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    }
2429481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2430481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    @Override
2431481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
2432481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        // ViewPagers should only report accessibility info for the current page,
2433481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        // otherwise things get very confusing.
2434481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2435481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        // TODO: Should this note something about the paging container?
2436481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2437481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        final int childCount = getChildCount();
2438481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        for (int i = 0; i < childCount; i++) {
2439481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            final View child = getChildAt(i);
2440481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            if (child.getVisibility() == VISIBLE) {
2441481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                final ItemInfo ii = infoForChild(child);
2442481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                if (ii != null && ii.position == mCurItem &&
2443481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                        child.dispatchPopulateAccessibilityEvent(event)) {
2444481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                    return true;
2445481243c175651c5de0741ab9390eb10f5b024d98Adam Powell                }
2446481243c175651c5de0741ab9390eb10f5b024d98Adam Powell            }
2447481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        }
2448481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
2449481243c175651c5de0741ab9390eb10f5b024d98Adam Powell        return false;
2450481243c175651c5de0741ab9390eb10f5b024d98Adam Powell    }
2451481243c175651c5de0741ab9390eb10f5b024d98Adam Powell
24528fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
24538fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
24548fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return new LayoutParams();
24558fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
24568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
24578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
24588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
24598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return generateDefaultLayoutParams();
24608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
24618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
24628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
24638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
24648fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        return p instanceof LayoutParams && super.checkLayoutParams(p);
24658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
24668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
24678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    @Override
24688fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
24691ccb8bcb79557d861de7f271c13e2fd8e54e012aAdam Powell        return new LayoutParams(getContext(), attrs);
24708fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
24718fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
247225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov    class MyAccessibilityDelegate extends AccessibilityDelegateCompat {
247325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
247425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        @Override
247525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
247625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            super.onInitializeAccessibilityEvent(host, event);
247725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            event.setClassName(ViewPager.class.getName());
247825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        }
247925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
248025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        @Override
248125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
248225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            super.onInitializeAccessibilityNodeInfo(host, info);
248325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            info.setClassName(ViewPager.class.getName());
248425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            info.setScrollable(mAdapter != null && mAdapter.getCount() > 1);
248525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            if (mAdapter != null && mCurItem >= 0 && mCurItem < mAdapter.getCount() - 1) {
248625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
248725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            }
248825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            if (mAdapter != null && mCurItem > 0 && mCurItem < mAdapter.getCount()) {
248925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
249025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            }
249125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        }
249225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
249325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        @Override
249425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        public boolean performAccessibilityAction(View host, int action, Bundle args) {
249525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            if (super.performAccessibilityAction(host, action, args)) {
249625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                return true;
249725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            }
249825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            switch (action) {
249925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: {
250025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                    if (mAdapter != null && mCurItem >= 0 && mCurItem < mAdapter.getCount() - 1) {
250125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                        setCurrentItem(mCurItem + 1);
250225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                        return true;
250325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                    }
250425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                } return false;
250525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: {
250625121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                    if (mAdapter != null && mCurItem > 0 && mCurItem < mAdapter.getCount()) {
250725121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                        setCurrentItem(mCurItem - 1);
250825121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                        return true;
250925121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                    }
251025121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov                } return false;
251125121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            }
251225121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov            return false;
251325121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov        }
251425121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov    }
251525121559b53b9f6c7ef7159203d42e11b9aee281Svetoslav Ganov
25168fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    private class PagerObserver extends DataSetObserver {
25178fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        @Override
25188fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onChanged() {
25198fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            dataSetChanged();
25208fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
25213661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        @Override
25228fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public void onInvalidated() {
25233661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell            dataSetChanged();
25243661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell        }
25253661ad6c9143d58f741568f940f77ca9d38dec47Adam Powell    }
25268fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
25277dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn    /**
25287dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * Layout parameters that should be supplied for views added to a
25297dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     * ViewPager.
25307dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn     */
25318fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    public static class LayoutParams extends ViewGroup.LayoutParams {
25328fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        /**
25338fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * true if this view is a decoration on the pager itself and not
25348fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         * a view supplied by the adapter.
25358fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell         */
25368fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public boolean isDecor;
25378fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2538a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
25393d9e557a9a9152db585264987d64f81fa86c73b5Dianne Hackborn         * Gravity setting for use on decor views only:
25407dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn         * Where to position the view page within the overall ViewPager
25417dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn         * container; constants are defined in {@link android.view.Gravity}.
2542a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
25438fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public int gravity;
25448fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
2545a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
2546a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * Width as a 0-1 multiplier of the measured pager width
2547a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
2548a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        public float widthFactor = 0.f;
2549a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
2550a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        /**
2551a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * true if this view was added during layout and needs to be measured
2552a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         * before being positioned.
2553a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell         */
2554a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell        public boolean needsMeasure;
2555a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell
25568fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public LayoutParams() {
25578fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            super(FILL_PARENT, FILL_PARENT);
25588fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
25598fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
25608fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        public LayoutParams(Context context, AttributeSet attrs) {
25618fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            super(context, attrs);
25628fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell
25638fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
2564a4a06a94df00575480d789b60ea25ce59184df1fAdam Powell            gravity = a.getInteger(0, Gravity.TOP);
25658fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell            a.recycle();
25668fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell        }
25678fffe01871be1806a1bdefa1f7213b660fcf5ac0Adam Powell    }
2568d59dd1decc75fb41e19928c21b90d25e3eda2559Dianne Hackborn}
2569