Index: chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java |
index 1c28167249e8777696c95251c21f5e1a4592b3e0..ba14bf5028325fa77ca6952825abf3d8a6122fdf 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java |
@@ -29,6 +29,9 @@ |
import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; |
import org.chromium.chrome.browser.util.ViewUtils; |
+import java.util.HashMap; |
+import java.util.Map; |
+ |
/** |
* Simple wrapper on top of a RecyclerView that will acquire focus when tapped. Ensures the |
* New Tab page receives focus when clicked. |
@@ -49,6 +52,13 @@ |
*/ |
private int mCompensationHeight; |
+ /** |
+ * Height compensation value for each item being dismissed. Since dismissals sometimes include |
+ * sibling elements, and these don't get the standard treatment, we track the total height |
+ * associated with the element the user interacted with. |
+ */ |
+ private final Map<ViewHolder, Integer> mCompensationHeightMap = new HashMap<>(); |
+ |
/** View used to calculate the position of the cards' snap point. */ |
private View mAboveTheFoldView; |
@@ -173,23 +183,23 @@ public void refreshBottomSpacing() { |
* below the fold to push the header up to to the top of the screen. |
*/ |
int calculateBottomSpacing() { |
- int firstHeaderPos = getNewTabPageAdapter().getFirstHeaderPosition(); |
+ int aboveTheFoldPosition = getNewTabPageAdapter().getAboveTheFoldPosition(); |
int firstVisiblePos = mLayoutManager.findFirstVisibleItemPosition(); |
- if (firstHeaderPos == RecyclerView.NO_POSITION |
+ if (aboveTheFoldPosition == RecyclerView.NO_POSITION |
|| firstVisiblePos == RecyclerView.NO_POSITION) { |
return 0; |
} |
- // We have enough items to fill the view, since the snap point item is not even visible. |
- if (firstVisiblePos > firstHeaderPos) { |
+ // We have enough items to fill the view, since the above-the-fold item is not even visible. |
+ if (firstVisiblePos > aboveTheFoldPosition) { |
return 0; |
} |
ViewHolder lastContentItem = findLastContentItem(); |
- ViewHolder firstHeader = findFirstHeader(); |
+ ViewHolder aboveTheFold = findViewHolderForAdapterPosition(aboveTheFoldPosition); |
int bottomSpacing = getHeight() - mToolbarHeight; |
- if (lastContentItem == null || firstHeader == null) { |
+ if (lastContentItem == null || aboveTheFold == null) { |
// This can happen in several cases, where some elements are not visible and the |
// RecyclerView didn't already attach them. We handle it by just adding space to make |
// sure that we never run out and force the UI to jump around and get stuck in a |
@@ -200,14 +210,14 @@ int calculateBottomSpacing() { |
// - Dismissing a snippet and having the status card coming to take its place. |
// - Refresh while being below the fold, for example by tapping the status card. |
- if (firstHeader != null) bottomSpacing -= firstHeader.itemView.getTop(); |
+ if (aboveTheFold != null) bottomSpacing -= aboveTheFold.itemView.getBottom(); |
Log.w(TAG, "The RecyclerView items are not attached, can't determine the content " |
+ "height: snap=%s, last=%s. Using full height: %d ", |
- firstHeader, lastContentItem, bottomSpacing); |
+ aboveTheFold, lastContentItem, bottomSpacing); |
} else { |
int contentHeight = |
- lastContentItem.itemView.getBottom() - firstHeader.itemView.getTop(); |
+ lastContentItem.itemView.getBottom() - aboveTheFold.itemView.getBottom(); |
bottomSpacing -= contentHeight - mCompensationHeight; |
} |
@@ -346,15 +356,28 @@ public NewTabPageLayout findAboveTheFoldView() { |
} |
/** Called when an item is in the process of being removed from the view. */ |
- public void onItemDismissStarted(View itemView) { |
- mCompensationHeight += itemView.getHeight(); |
+ public void onItemDismissStarted(ViewHolder viewHolder) { |
+ assert !mCompensationHeightMap.containsKey(viewHolder); |
+ |
+ int dismissedHeight = viewHolder.itemView.getHeight(); |
+ |
+ ViewHolder siblingViewHolder = getNewTabPageAdapter().getDismissSibling(viewHolder); |
+ if (siblingViewHolder != null) { |
+ dismissedHeight += siblingViewHolder.itemView.getHeight(); |
+ } |
+ |
+ mCompensationHeightMap.put(viewHolder, dismissedHeight); |
+ mCompensationHeight += dismissedHeight; |
refreshBottomSpacing(); |
} |
/** Called when an item has finished being removed from the view. */ |
- public void onItemDismissFinished(View itemView) { |
- mCompensationHeight -= itemView.getHeight(); |
+ public void onItemDismissFinished(ViewHolder viewHolder) { |
+ assert mCompensationHeightMap.containsKey(viewHolder); |
+ mCompensationHeight -= mCompensationHeightMap.remove(viewHolder); |
+ |
assert mCompensationHeight >= 0; |
+ refreshBottomSpacing(); |
} |
/** |
@@ -403,8 +426,13 @@ public void snapScroll(View fakeBox, int parentScrollY, int parentHeight) { |
if (peekingCardViewHolder != null && isFirstItemVisible()) { |
if (!mHasSpaceForPeekingCard) return; |
+ ViewHolder firstHeaderViewHolder = findFirstHeader(); |
+ // It is possible to have a card but no header, for example the sign in promo. |
+ // That one does not peek. |
+ if (firstHeaderViewHolder == null) return; |
+ |
View peekingCardView = peekingCardViewHolder.itemView; |
- View headerView = findFirstHeader().itemView; |
+ View headerView = firstHeaderViewHolder.itemView; |
final int peekingHeight = getResources().getDimensionPixelSize( |
R.dimen.snippets_padding_and_peeking_card_height); |
@@ -474,13 +502,13 @@ public void dismissItemWithAnimation(SnippetArticle suggestion) { |
animation.addListener(new AnimatorListenerAdapter() { |
@Override |
public void onAnimationStart(Animator animation) { |
- NewTabPageRecyclerView.this.onItemDismissStarted(itemView); |
+ NewTabPageRecyclerView.this.onItemDismissStarted(viewHolder); |
} |
@Override |
public void onAnimationEnd(Animator animation) { |
getNewTabPageAdapter().dismissItem(position); |
- NewTabPageRecyclerView.this.onItemDismissFinished(itemView); |
+ NewTabPageRecyclerView.this.onItemDismissFinished(viewHolder); |
} |
}); |
animation.start(); |