From 90b1a40d910cf9926b8f5d9d10663730e005451f Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Tue, 14 Jun 2011 17:50:39 -0700 Subject: [PATCH 1/6] Fix NPE in ViewPager.onSaveInstanceState Change-Id: Ifee62477291f970873b5fdeba8336800d1b8643e --- v4/java/android/support/v4/view/ViewPager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java index 8525a7c46b8e..169e829f024f 100644 --- a/v4/java/android/support/v4/view/ViewPager.java +++ b/v4/java/android/support/v4/view/ViewPager.java @@ -456,7 +456,9 @@ public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.position = mCurItem; - ss.adapterState = mAdapter.saveState(); + if (mAdapter != null) { + ss.adapterState = mAdapter.saveState(); + } return ss; } From 62e6c754f05f87a557c49ae37643e887d0e58f79 Mon Sep 17 00:00:00 2001 From: Minh Pham Date: Thu, 16 Jun 2011 10:57:28 -0700 Subject: [PATCH 2/6] Cleanup ViewPager when switch adapter - Destroy all items in the old adapter - Clear the internal list of items - remove all views Change-Id: I9608b03bd2b2fcb1949f8c7c2d59d49914d27508 --- v4/java/android/support/v4/view/ViewPager.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java index c80e6b717a44..413d8f1abc5c 100644 --- a/v4/java/android/support/v4/view/ViewPager.java +++ b/v4/java/android/support/v4/view/ViewPager.java @@ -213,6 +213,15 @@ private void setScrollState(int newState) { public void setAdapter(PagerAdapter adapter) { if (mAdapter != null) { mAdapter.setDataSetObserver(null); + mAdapter.startUpdate(this); + for (int i = 0; i < mItems.size(); i++) { + final ItemInfo ii = mItems.get(i); + mAdapter.destroyItem(this, ii.position, ii.object); + } + mAdapter.finishUpdate(this); + mItems.clear(); + removeAllViews(); + mCurItem = 0; } mAdapter = adapter; From 54bdb7954141a06e488854e96f21372d59c4c951 Mon Sep 17 00:00:00 2001 From: Minh Pham Date: Thu, 16 Jun 2011 15:25:00 -0700 Subject: [PATCH 3/6] Reset scroll position when clear state - Scroll to (0, 0) when setting adapter to null. Bug: 4690349 Change-Id: Ia06d079b86491696d7509385e08ce7d1227177b1 --- v4/java/android/support/v4/view/ViewPager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java index 413d8f1abc5c..a84a86a35ab3 100644 --- a/v4/java/android/support/v4/view/ViewPager.java +++ b/v4/java/android/support/v4/view/ViewPager.java @@ -222,6 +222,7 @@ public void setAdapter(PagerAdapter adapter) { mItems.clear(); removeAllViews(); mCurItem = 0; + scrollTo(0, 0); } mAdapter = adapter; From 4b1c5a30f6107b6d170ec900f1d56bd7c46a10b7 Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Thu, 16 Jun 2011 11:45:57 -0700 Subject: [PATCH 4/6] Add ViewaPager.getCurrentItem Change-Id: I9ae744e2ed081866589b6ad8f3767e199b2dd148 --- v4/java/android/support/v4/view/ViewPager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java index a84a86a35ab3..b747ab0f289b 100644 --- a/v4/java/android/support/v4/view/ViewPager.java +++ b/v4/java/android/support/v4/view/ViewPager.java @@ -254,6 +254,10 @@ public void setCurrentItem(int item) { setCurrentItemInternal(item, true, false); } + public int getCurrentItem() { + return mCurItem; + } + void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { if (mAdapter == null || mAdapter.getCount() <= 0) { setScrollingCacheEnabled(false); From b26834d698d7c1ef48cecdca707517bd6be2aec0 Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Mon, 31 Oct 2011 11:40:33 -0700 Subject: [PATCH 5/6] Bug 5535639 - Monkeys mad at FragmentManager Also check for starting deferred start fragments when a loader is destroyed. Change-Id: I58c80708f96afa2943ca1e2cae077f7ac52a064d --- v4/java/android/support/v4/app/FragmentManager.java | 2 ++ v4/java/android/support/v4/app/LoaderManager.java | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/v4/java/android/support/v4/app/FragmentManager.java b/v4/java/android/support/v4/app/FragmentManager.java index 32356e543885..20c4b66deee7 100644 --- a/v4/java/android/support/v4/app/FragmentManager.java +++ b/v4/java/android/support/v4/app/FragmentManager.java @@ -1081,6 +1081,8 @@ void moveToState(int newState, int transit, int transitStyle, boolean always) { } void startPendingDeferredFragments() { + if (mActive == null) return; + for (int i=0; i Date: Wed, 9 Nov 2011 17:18:14 -0800 Subject: [PATCH 6/6] Fix bug 5547745 - Use Launcher Workspace style for ViewPager fling behavior Change-Id: Ib3fd7875bd951685830e1c28329894ae6f9d02ae --- .../android/support/v4/view/ViewPager.java | 65 +++++++++++-------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java index c3cbb62a03b2..92ab27f6f976 100644 --- a/v4/java/android/support/v4/view/ViewPager.java +++ b/v4/java/android/support/v4/view/ViewPager.java @@ -67,6 +67,7 @@ public class ViewPager extends ViewGroup { private static final int DEFAULT_OFFSCREEN_PAGES = 1; private static final int MAX_SETTLE_DURATION = 600; // ms + private static final int MIN_DISTANCE_FOR_FLING = 25; // dips private static final int[] LAYOUT_ATTRS = new int[] { android.R.attr.layout_gravity @@ -86,10 +87,8 @@ public int compare(ItemInfo lhs, ItemInfo rhs) { private static final Interpolator sInterpolator = new Interpolator() { public float getInterpolation(float t) { - // _o(t) = t * t * ((tension + 1) * t + tension) - // o(t) = _o(t - 1) + 1 t -= 1.0f; - return t * t * t + 1.0f; + return t * t * t * t * t + 1.0f; } }; @@ -115,7 +114,6 @@ public float getInterpolation(float t) { private boolean mScrollingCacheEnabled; private boolean mPopulatePending; - private boolean mIsPopulating; private boolean mScrolling; private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; @@ -145,8 +143,7 @@ public float getInterpolation(float t) { private VelocityTracker mVelocityTracker; private int mMinimumVelocity; private int mMaximumVelocity; - private float mBaseLineFlingVelocity; - private float mFlingVelocityInfluence; + private int mFlingDistance; private boolean mFakeDragging; private long mFakeDragBeginTime; @@ -275,9 +272,8 @@ void initViewPager() { mLeftEdge = new EdgeEffectCompat(context); mRightEdge = new EdgeEffectCompat(context); - float density = context.getResources().getDisplayMetrics().density; - mBaseLineFlingVelocity = 2500.0f * density; - mFlingVelocityInfluence = 0.4f; + final float density = context.getResources().getDisplayMetrics().density; + mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); } private void setScrollState(int newState) { @@ -609,14 +605,19 @@ void smoothScrollTo(int x, int y, int velocity) { mScrolling = true; setScrollState(SCROLL_STATE_SETTLING); - final float pageDelta = (float) Math.abs(dx) / (getWidth() + mPageMargin); - int duration = (int) (pageDelta * 100); + final int width = getWidth(); + final int halfWidth = width / 2; + final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); + final float distance = halfWidth + halfWidth * + distanceInfluenceForSnapDuration(distanceRatio); + int duration = 0; velocity = Math.abs(velocity); if (velocity > 0) { - duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence; + duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); } else { - duration += 100; + final float pageDelta = (float) Math.abs(dx) / (width + mPageMargin); + duration = (int) ((pageDelta + 1) * 100); } duration = Math.min(duration, MAX_SETTLE_DURATION); @@ -718,7 +719,6 @@ void populate() { return; } - mIsPopulating = true; mAdapter.startUpdate(this); final int pageLimit = mOffscreenPageLimit; @@ -784,7 +784,6 @@ void populate() { mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); mAdapter.finishUpdate(this); - mIsPopulating = false; if (hasFocus()) { View currentFocused = findFocus(); @@ -1495,7 +1494,13 @@ public boolean onTouchEvent(MotionEvent ev) { final int widthWithMargin = getWidth() + mPageMargin; final int scrollX = getScrollX(); final int currentPage = scrollX / widthWithMargin; - int nextPage = initialVelocity > 0 ? currentPage : currentPage + 1; + final float pageOffset = (float) (scrollX % widthWithMargin) / widthWithMargin; + final int activePointerIndex = + MotionEventCompat.findPointerIndex(ev, mActivePointerId); + final float x = MotionEventCompat.getX(ev, activePointerIndex); + final int totalDelta = (int) (x - mInitialMotionX); + int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, + totalDelta); setCurrentItemInternal(nextPage, true, true, initialVelocity); mActivePointerId = INVALID_POINTER; @@ -1530,6 +1535,17 @@ public boolean onTouchEvent(MotionEvent ev) { return true; } + private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) { + int targetPage; + if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { + targetPage = velocity > 0 ? currentPage : currentPage + 1; + } else { + targetPage = (int) (currentPage + pageOffset + 0.5f); + } + + return targetPage; + } + @Override public void draw(Canvas canvas) { super.draw(canvas); @@ -1645,16 +1661,13 @@ public void endFakeDrag() { int initialVelocity = (int)VelocityTrackerCompat.getYVelocity( velocityTracker, mActivePointerId); mPopulatePending = true; - if ((Math.abs(initialVelocity) > mMinimumVelocity) - || Math.abs(mInitialMotionX-mLastMotionX) >= (getWidth()/3)) { - if (mLastMotionX > mInitialMotionX) { - setCurrentItemInternal(mCurItem-1, true, true); - } else { - setCurrentItemInternal(mCurItem+1, true, true); - } - } else { - setCurrentItemInternal(mCurItem, true, true); - } + final int totalDelta = (int) (mLastMotionX - mInitialMotionX); + final int scrollX = getScrollX(); + final int widthWithMargin = getWidth() + mPageMargin; + final int currentPage = scrollX / widthWithMargin; + final float pageOffset = (float) (scrollX % widthWithMargin) / widthWithMargin; + int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, totalDelta); + setCurrentItemInternal(nextPage, true, true, initialVelocity); endDrag(); mFakeDragging = false;