| 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 72bbdee20dee6efaca228843ab431f77f89f90fa..56073eb873ebab2a771b054d55267835a6a1170f 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;
|
|
|
| @@ -171,23 +181,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
|
| @@ -198,14 +208,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;
|
| }
|
|
|
| @@ -344,15 +354,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();
|
| }
|
|
|
| /**
|
| @@ -401,8 +424,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);
|
|
|
| @@ -472,13 +500,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();
|
|
|