Commit 76d61d37 authored by dgn's avatar dgn Committed by Commit bot

[NTP Client][Reland]Use the separate button style for the NoArticles status

Original issue's description:
> [NTP Client] Use the separate button style for the NoArticles status
>
> Makes the articles and bookmarks sections use the same style of status
> card when they have no snippets.
>
> the hasMoreButton property of categories now only determines whether
> the action item will be shown when there are suggestions to display.
>
> This patch also lets the SuggestionsCategoryInfo be aware of the
> current category it is describing, and moves various category specific
> behaviours into the SuggestionsCategoryInfo class.
>
> Preview: https://goo.gl/photos/VhceT6cjvME6QS8m7
>
> BUG=649670
>
> Committed: https://crrev.com/ffa8e3905fed0b1df0d56ab6e4b17791b31cd171
> Cr-Commit-Position: refs/heads/master@{#423517}

> Revert Data:
> Committed: https://crrev.com/b5e8956c2c8a10484d10a117b3ef5a33ee58cb6c
> Cr-Commit-Position: refs/heads/master@{#423573}

BUG=649670

Review-Url: https://codereview.chromium.org/2401643004
Cr-Commit-Position: refs/heads/master@{#423863}
parent 12596183
...@@ -6,11 +6,9 @@ package org.chromium.chrome.browser.ntp.cards; ...@@ -6,11 +6,9 @@ package org.chromium.chrome.browser.ntp.cards;
import android.view.View; import android.view.View;
import org.chromium.base.Log;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
import org.chromium.chrome.browser.ntp.UiConfig; import org.chromium.chrome.browser.ntp.UiConfig;
import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
/** /**
* Item that allows the user to perform an action on the NTP. * Item that allows the user to perform an action on the NTP.
...@@ -18,15 +16,15 @@ import org.chromium.chrome.browser.ntp.snippets.KnownCategories; ...@@ -18,15 +16,15 @@ import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
class ActionItem implements NewTabPageItem { class ActionItem implements NewTabPageItem {
private static final String TAG = "NtpCards"; private static final String TAG = "NtpCards";
private final int mCategory; private final SuggestionsCategoryInfo mCategoryInfo;
// The position (index) of this item within its section, for logging purposes. // The position (index) of this item within its section, for logging purposes.
private int mPosition; private int mPosition;
private boolean mImpressionTracked = false; private boolean mImpressionTracked = false;
private boolean mDismissable; private boolean mDismissable;
public ActionItem(int category) { public ActionItem(SuggestionsCategoryInfo categoryInfo) {
mCategory = category; mCategoryInfo = categoryInfo;
} }
@Override @Override
...@@ -45,31 +43,19 @@ class ActionItem implements NewTabPageItem { ...@@ -45,31 +43,19 @@ class ActionItem implements NewTabPageItem {
public static class ViewHolder extends CardViewHolder { public static class ViewHolder extends CardViewHolder {
private ActionItem mActionListItem; private ActionItem mActionListItem;
public ViewHolder(final NewTabPageRecyclerView recyclerView,
public ViewHolder(NewTabPageRecyclerView recyclerView, final NewTabPageManager manager, final NewTabPageManager manager, UiConfig uiConfig) {
UiConfig uiConfig) {
super(R.layout.new_tab_page_action_card, recyclerView, uiConfig); super(R.layout.new_tab_page_action_card, recyclerView, uiConfig);
itemView.findViewById(R.id.action_button) itemView.findViewById(R.id.action_button)
.setOnClickListener(new View.OnClickListener() { .setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
int category = mActionListItem.mCategory; int category = mActionListItem.mCategoryInfo.getCategory();
manager.trackSnippetCategoryActionClick( manager.trackSnippetCategoryActionClick(
category, mActionListItem.mPosition); category, mActionListItem.mPosition);
if (category == KnownCategories.BOOKMARKS) { mActionListItem.mCategoryInfo.performEmptyStateAction(
manager.navigateToBookmarks(); manager, recyclerView.getNewTabPageAdapter());
} else if (category == KnownCategories.DOWNLOADS) {
manager.navigateToDownloadManager();
} else if (category == KnownCategories.FOREIGN_TABS) {
manager.navigateToRecentTabs();
} else {
// TODO(pke): This should redirect to the C++ backend. Once it does,
// change the condition in the SuggestionsSection constructor.
Log.wtf(TAG,
"More action called on a dynamically added section: %d",
category);
}
} }
}); });
...@@ -79,7 +65,8 @@ class ActionItem implements NewTabPageItem { ...@@ -79,7 +65,8 @@ class ActionItem implements NewTabPageItem {
if (mActionListItem != null && !mActionListItem.mImpressionTracked) { if (mActionListItem != null && !mActionListItem.mImpressionTracked) {
mActionListItem.mImpressionTracked = true; mActionListItem.mImpressionTracked = true;
manager.trackSnippetCategoryActionImpression( manager.trackSnippetCategoryActionImpression(
mActionListItem.mCategory, mActionListItem.mPosition); mActionListItem.mCategoryInfo.getCategory(),
mActionListItem.mPosition);
} }
} }
}); });
......
...@@ -211,7 +211,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> ...@@ -211,7 +211,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder>
SuggestionsSection section = mSections.get(category); SuggestionsSection section = mSections.get(category);
if (section == null) { if (section == null) {
section = new SuggestionsSection(category, info, this); section = new SuggestionsSection(info, this);
mSections.put(category, section); mSections.put(category, section);
} }
......
...@@ -5,118 +5,33 @@ ...@@ -5,118 +5,33 @@
package org.chromium.chrome.browser.ntp.cards; package org.chromium.chrome.browser.ntp.cards;
import android.content.Context; import android.content.Context;
import android.support.annotation.Nullable;
import org.chromium.base.Log;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum;
/** /**
* Card that is shown when the user needs to be made aware of some information about their * Card that is shown when the user needs to be made aware of some information about their
* configuration about the NTP suggestions: there is no more available suggested content, sync * configuration that affects the NTP suggestions.
* should be enabled, etc.
*/ */
public abstract class StatusItem implements NewTabPageItem { public class StatusItem implements NewTabPageItem {
/**
* Delegate to provide the status cards a way to interact with the rest of the system: tap
* handler, etc.
*/
public interface ActionDelegate { void onButtonTapped(); }
private static class NoBookmarks extends StatusItem {
public NoBookmarks() {
super(R.string.ntp_status_card_title_no_bookmarks,
R.string.ntp_status_card_no_bookmarks, 0);
Log.d(TAG, "Registering card for status: No Bookmarks");
}
@Override
protected void performAction(Context context) {
assert false; // not reached.
}
@Override
protected boolean hasAction() {
return false;
}
}
private static class NoSnippets extends StatusItem {
private final ActionDelegate mActionDelegate;
public NoSnippets(ActionDelegate actionDelegate) {
super(R.string.ntp_status_card_title_no_articles, R.string.ntp_status_card_no_articles,
R.string.reload);
mActionDelegate = actionDelegate;
Log.d(TAG, "Registering card for status: No Snippets");
}
@Override
protected void performAction(Context context) {
mActionDelegate.onButtonTapped();
}
}
private static final String TAG = "NtpCards";
private final int mHeaderStringId; private final int mHeaderStringId;
private final int mDescriptionStringId; private final int mDescriptionStringId;
private final int mActionStringId; private final int mActionStringId;
public static StatusItem create(
@CategoryStatusEnum int categoryStatus, @Nullable ActionDelegate actionDelegate) {
switch (categoryStatus) {
case CategoryStatus.SIGNED_OUT:
// Fall through. Sign out is a transitive state that we just use to clear content.
case CategoryStatus.AVAILABLE:
case CategoryStatus.AVAILABLE_LOADING:
case CategoryStatus.INITIALIZING:
// TODO(dgn): rewrite this whole thing? Get one card and change its state instead
// of recreating it. It would be more flexible in terms of adapting the content
// to different usages.
return actionDelegate == null ? new NoBookmarks() : new NoSnippets(actionDelegate);
case CategoryStatus.ALL_SUGGESTIONS_EXPLICITLY_DISABLED:
Log.wtf(TAG, "Attempted to create a status card while the feature should be off.");
return null;
case CategoryStatus.CATEGORY_EXPLICITLY_DISABLED:
// In this case, the entire section should have been cleared off the UI.
Log.wtf(TAG, "Attempted to create a status card for content suggestions "
+ " when the category status is CATEGORY_EXPLICITLY_DISABLED.");
return null;
case CategoryStatus.NOT_PROVIDED:
// In this case, the UI should remain as it is and also keep the previous category
// status, so the NOT_PROVIDED should never reach here.
Log.wtf(TAG, "Attempted to create a status card for content suggestions "
+ " when the category is NOT_PROVIDED.");
return null;
case CategoryStatus.LOADING_ERROR:
// In this case, the entire section should have been cleared off the UI.
Log.wtf(TAG, "Attempted to create a status card for content suggestions "
+ " when the category is LOADING_ERROR.");
return null;
default:
Log.wtf(TAG, "Attempted to create a status card for an unknown value: %d",
categoryStatus);
return null;
}
}
protected StatusItem(int headerStringId, int descriptionStringId, int actionStringId) { protected StatusItem(int headerStringId, int descriptionStringId, int actionStringId) {
mHeaderStringId = headerStringId; mHeaderStringId = headerStringId;
mDescriptionStringId = descriptionStringId; mDescriptionStringId = descriptionStringId;
mActionStringId = actionStringId; mActionStringId = actionStringId;
} }
protected abstract void performAction(Context context); public static StatusItem createNoSuggestionsItem(SuggestionsCategoryInfo categoryInfo) {
return new StatusItem(R.string.ntp_status_card_title_no_suggestions,
categoryInfo.getNoSuggestionDescription(), 0);
}
protected void performAction(Context context) {}
protected boolean hasAction() { protected boolean hasAction() {
return true; return mActionStringId != 0;
} }
@Override @Override
......
...@@ -4,13 +4,29 @@ ...@@ -4,13 +4,29 @@
package org.chromium.chrome.browser.ntp.cards; package org.chromium.chrome.browser.ntp.cards;
import android.support.annotation.StringRes;
import org.chromium.base.Log;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout.ContentSuggestionsCardLayoutEnum; import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout.ContentSuggestionsCardLayoutEnum;
import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
/** /**
* Contains static meta information about a Category. Equivalent of the CategoryInfo class in * Contains meta information about a Category. Equivalent of the CategoryInfo class in
* components/ntp_snippets/category_info.h. * components/ntp_snippets/category_info.h.
*/ */
public class SuggestionsCategoryInfo { public class SuggestionsCategoryInfo {
private static final String TAG = "NtpCards";
/**
* Id of the category.
*/
@CategoryInt
private final int mCategory;
/** /**
* Localized title of the category. * Localized title of the category.
*/ */
...@@ -32,8 +48,10 @@ public class SuggestionsCategoryInfo { ...@@ -32,8 +48,10 @@ public class SuggestionsCategoryInfo {
/** Whether this category should be shown if it offers no suggestions. */ /** Whether this category should be shown if it offers no suggestions. */
private final boolean mShowIfEmpty; private final boolean mShowIfEmpty;
public SuggestionsCategoryInfo(String title, @ContentSuggestionsCardLayoutEnum int cardLayout, public SuggestionsCategoryInfo(@CategoryInt int category, String title,
boolean hasMoreButton, boolean showIfEmpty) { @ContentSuggestionsCardLayoutEnum int cardLayout, boolean hasMoreButton,
boolean showIfEmpty) {
mCategory = category;
mTitle = title; mTitle = title;
mCardLayout = cardLayout; mCardLayout = cardLayout;
mHasMoreButton = hasMoreButton; mHasMoreButton = hasMoreButton;
...@@ -44,6 +62,11 @@ public class SuggestionsCategoryInfo { ...@@ -44,6 +62,11 @@ public class SuggestionsCategoryInfo {
return mTitle; return mTitle;
} }
@CategoryInt
public int getCategory() {
return mCategory;
}
@ContentSuggestionsCardLayoutEnum @ContentSuggestionsCardLayoutEnum
public int getCardLayout() { public int getCardLayout() {
return mCardLayout; return mCardLayout;
...@@ -56,4 +79,46 @@ public class SuggestionsCategoryInfo { ...@@ -56,4 +79,46 @@ public class SuggestionsCategoryInfo {
public boolean showIfEmpty() { public boolean showIfEmpty() {
return mShowIfEmpty; return mShowIfEmpty;
} }
/**
* Performs the appropriate action for the provided category, for the case where there are no
* suggestions available. In general, this consists in navigating to the view showing all the
* content, or fetching new content.
*/
public void performEmptyStateAction(NewTabPageManager manager, NewTabPageAdapter adapter) {
switch (mCategory) {
case KnownCategories.ARTICLES:
adapter.reloadSnippets();
break;
case KnownCategories.BOOKMARKS:
manager.navigateToBookmarks();
break;
case KnownCategories.DOWNLOADS:
manager.navigateToDownloadManager();
break;
case KnownCategories.FOREIGN_TABS:
manager.navigateToRecentTabs();
break;
default:
Log.wtf(TAG, "'Empty State' action called for unsupported category: %d", mCategory);
break;
}
}
/**
* Returns the string to use as description for the status card that is displayed when there
* are no suggestions available for the provided category.
*/
@StringRes
public int getNoSuggestionDescription() {
switch (mCategory) {
case KnownCategories.ARTICLES:
return R.string.ntp_status_card_no_articles;
case KnownCategories.BOOKMARKS:
return R.string.ntp_status_card_no_bookmarks;
default:
Log.wtf(TAG, "Requested description for unsupported category: %d", mCategory);
return 0;
}
}
} }
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
package org.chromium.chrome.browser.ntp.cards; package org.chromium.chrome.browser.ntp.cards;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ntp.cards.StatusItem.ActionDelegate;
import org.chromium.chrome.browser.ntp.snippets.CategoryInt; import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum; import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum;
import org.chromium.chrome.browser.ntp.snippets.SectionHeader; import org.chromium.chrome.browser.ntp.snippets.SectionHeader;
...@@ -22,39 +21,18 @@ import java.util.List; ...@@ -22,39 +21,18 @@ import java.util.List;
public class SuggestionsSection implements ItemGroup { public class SuggestionsSection implements ItemGroup {
private final List<SnippetArticle> mSuggestions = new ArrayList<>(); private final List<SnippetArticle> mSuggestions = new ArrayList<>();
private final SectionHeader mHeader; private final SectionHeader mHeader;
private StatusItem mStatus; private final StatusItem mStatus;
private final ProgressItem mProgressIndicator = new ProgressItem(); private final ProgressItem mProgressIndicator = new ProgressItem();
private final ActionDelegate mActionDelegate;
private final ActionItem mMoreButton; private final ActionItem mMoreButton;
@CategoryInt
private final int mCategory;
private final Observer mObserver; private final Observer mObserver;
private final SuggestionsCategoryInfo mCategoryInfo;
public SuggestionsSection(@CategoryInt int category, SuggestionsCategoryInfo info, public SuggestionsSection(SuggestionsCategoryInfo info, Observer observer) {
final NewTabPageAdapter adapter) {
this(category, info, adapter, new ActionDelegate() {
@Override
public void onButtonTapped() {
adapter.reloadSnippets();
}
});
}
@VisibleForTesting
SuggestionsSection(@CategoryInt int category, SuggestionsCategoryInfo info, Observer observer,
ActionDelegate actionDelegate) {
mHeader = new SectionHeader(info.getTitle()); mHeader = new SectionHeader(info.getTitle());
mCategory = category; mCategoryInfo = info;
mObserver = observer; mObserver = observer;
mMoreButton = new ActionItem(info);
// TODO(dgn): Properly define strings, actions, etc. for each section and category type. mStatus = StatusItem.createNoSuggestionsItem(info);
if (info.hasMoreButton()) {
mMoreButton = new ActionItem(category);
mActionDelegate = null;
} else {
mMoreButton = null;
mActionDelegate = actionDelegate;
}
} }
@Override @Override
...@@ -65,7 +43,7 @@ public class SuggestionsSection implements ItemGroup { ...@@ -65,7 +43,7 @@ public class SuggestionsSection implements ItemGroup {
items.addAll(mSuggestions); items.addAll(mSuggestions);
if (mSuggestions.isEmpty()) items.add(mStatus); if (mSuggestions.isEmpty()) items.add(mStatus);
if (mMoreButton != null) items.add(mMoreButton); if (mCategoryInfo.hasMoreButton() || mSuggestions.isEmpty()) items.add(mMoreButton);
if (mSuggestions.isEmpty()) items.add(mProgressIndicator); if (mSuggestions.isEmpty()) items.add(mProgressIndicator);
return Collections.unmodifiableList(items); return Collections.unmodifiableList(items);
...@@ -82,12 +60,14 @@ public class SuggestionsSection implements ItemGroup { ...@@ -82,12 +60,14 @@ public class SuggestionsSection implements ItemGroup {
int globalRemovedIndex = removedIndex + 1; // Header has index 0 in the section. int globalRemovedIndex = removedIndex + 1; // Header has index 0 in the section.
mObserver.notifyItemRemoved(this, globalRemovedIndex); mObserver.notifyItemRemoved(this, globalRemovedIndex);
if (!hasSuggestions()) { // If we still have some suggestions, we are done. Otherwise, we'll have to notify about the
// When the last suggestion is removed, we insert other items to display the status, // status-related items that are now present.
// notify about them too. if (hasSuggestions()) return;
mObserver.notifyItemInserted(this, globalRemovedIndex); mObserver.notifyItemInserted(this, globalRemovedIndex); // Status card.
mObserver.notifyItemInserted(this, globalRemovedIndex + (mMoreButton == null ? 1 : 2)); if (!mCategoryInfo.hasMoreButton()) {
mObserver.notifyItemInserted(this, globalRemovedIndex + 1); // Action card.
} }
mObserver.notifyItemInserted(this, globalRemovedIndex + 2); // Progress indicator.
} }
public void removeSuggestionById(String idWithinCategory) { public void removeSuggestionById(String idWithinCategory) {
...@@ -118,6 +98,7 @@ public class SuggestionsSection implements ItemGroup { ...@@ -118,6 +98,7 @@ public class SuggestionsSection implements ItemGroup {
if (mMoreButton != null) { if (mMoreButton != null) {
mMoreButton.setPosition(mSuggestions.size()); mMoreButton.setPosition(mSuggestions.size());
mMoreButton.setDismissable(mSuggestions.isEmpty());
} }
mObserver.notifyGroupChanged(this, itemCountBefore, getItems().size()); mObserver.notifyGroupChanged(this, itemCountBefore, getItems().size());
} }
...@@ -130,15 +111,14 @@ public class SuggestionsSection implements ItemGroup { ...@@ -130,15 +111,14 @@ public class SuggestionsSection implements ItemGroup {
} }
private void setStatusInternal(@CategoryStatusEnum int status) { private void setStatusInternal(@CategoryStatusEnum int status) {
mStatus = StatusItem.create(status, mActionDelegate);
if (!SnippetsBridge.isCategoryStatusAvailable(status)) mSuggestions.clear(); if (!SnippetsBridge.isCategoryStatusAvailable(status)) mSuggestions.clear();
mProgressIndicator.setVisible(SnippetsBridge.isCategoryLoading(status)); mProgressIndicator.setVisible(SnippetsBridge.isCategoryLoading(status));
} }
@CategoryInt
public int getCategory() { public int getCategory() {
return mCategory; return mCategoryInfo.getCategory();
} }
private void copyThumbnails(List<SnippetArticle> suggestions) { private void copyThumbnails(List<SnippetArticle> suggestions) {
......
...@@ -202,9 +202,9 @@ public class SnippetsBridge implements SuggestionsSource { ...@@ -202,9 +202,9 @@ public class SnippetsBridge implements SuggestionsSource {
} }
@CalledByNative @CalledByNative
private static SuggestionsCategoryInfo createSuggestionsCategoryInfo( private static SuggestionsCategoryInfo createSuggestionsCategoryInfo(int category, String title,
String title, int cardLayout, boolean hasMoreButton, boolean showIfEmpty) { int cardLayout, boolean hasMoreButton, boolean showIfEmpty) {
return new SuggestionsCategoryInfo(title, cardLayout, hasMoreButton, showIfEmpty); return new SuggestionsCategoryInfo(category, title, cardLayout, hasMoreButton, showIfEmpty);
} }
@CalledByNative @CalledByNative
......
...@@ -173,8 +173,9 @@ public class ArticleSnippetsTest extends ChromeActivityTestCaseBase<ChromeActivi ...@@ -173,8 +173,9 @@ public class ArticleSnippetsTest extends ChromeActivityTestCaseBase<ChromeActivi
0, // Position 0, // Position
ContentSuggestionsCardLayout.MINIMAL_CARD); ContentSuggestionsCardLayout.MINIMAL_CARD);
mSnippetsSource.setInfoForCategory(KnownCategories.ARTICLES, new SuggestionsCategoryInfo( mSnippetsSource.setInfoForCategory(KnownCategories.ARTICLES,
"Section Title", ContentSuggestionsCardLayout.FULL_CARD, false, true)); new SuggestionsCategoryInfo(KnownCategories.ARTICLES, "Section Title",
ContentSuggestionsCardLayout.FULL_CARD, false, true));
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.AVAILABLE); CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.ntp.cards; package org.chromium.chrome.browser.ntp.cards;
import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout; import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout;
import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
...@@ -25,13 +26,15 @@ public final class ContentSuggestionsTestUtils { ...@@ -25,13 +26,15 @@ public final class ContentSuggestionsTestUtils {
return suggestions; return suggestions;
} }
public static SuggestionsCategoryInfo createInfo(boolean moreButton, boolean showIfEmpty) { public static SuggestionsCategoryInfo createInfo(
@CategoryInt int category, boolean moreButton, boolean showIfEmpty) {
return new SuggestionsCategoryInfo( return new SuggestionsCategoryInfo(
"", ContentSuggestionsCardLayout.FULL_CARD, moreButton, showIfEmpty); category, "", ContentSuggestionsCardLayout.FULL_CARD, moreButton, showIfEmpty);
} }
public static SuggestionsSection createSection( public static SuggestionsSection createSection(
boolean moreButton, boolean showIfEmpty, ItemGroup.Observer observer) { boolean moreButton, boolean showIfEmpty, ItemGroup.Observer observer) {
return new SuggestionsSection(42, createInfo(moreButton, showIfEmpty), observer, null); SuggestionsCategoryInfo info = createInfo(42, moreButton, showIfEmpty);
return new SuggestionsSection(info, observer);
} }
} }
...@@ -33,6 +33,7 @@ import org.robolectric.annotation.Config; ...@@ -33,6 +33,7 @@ import org.robolectric.annotation.Config;
import static org.chromium.base.test.util.Matchers.greaterThanOrEqualTo; import static org.chromium.base.test.util.Matchers.greaterThanOrEqualTo;
import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils
.createDummySuggestions; .createDummySuggestions;
import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createInfo;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
...@@ -57,7 +58,6 @@ import org.chromium.chrome.browser.signin.SigninManager; ...@@ -57,7 +58,6 @@ import org.chromium.chrome.browser.signin.SigninManager;
import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver; import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
import org.chromium.testing.local.LocalRobolectricTestRunner; import org.chromium.testing.local.LocalRobolectricTestRunner;
import java.nio.channels.UnsupportedAddressTypeException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
...@@ -120,9 +120,7 @@ public class NewTabPageAdapterTest { ...@@ -120,9 +120,7 @@ public class NewTabPageAdapterTest {
expect(NewTabPageItem.VIEW_TYPE_HEADER); expect(NewTabPageItem.VIEW_TYPE_HEADER);
if (descriptor.mStatusCard) { if (descriptor.mStatusCard) {
expect(NewTabPageItem.VIEW_TYPE_STATUS); expect(NewTabPageItem.VIEW_TYPE_STATUS);
if (descriptor.mMoreButton) {
expect(NewTabPageItem.VIEW_TYPE_ACTION); expect(NewTabPageItem.VIEW_TYPE_ACTION);
}
expect(NewTabPageItem.VIEW_TYPE_PROGRESS); expect(NewTabPageItem.VIEW_TYPE_PROGRESS);
} else { } else {
for (int i = 1; i <= descriptor.mNumSuggestions; i++) { for (int i = 1; i <= descriptor.mNumSuggestions; i++) {
...@@ -225,11 +223,11 @@ public class NewTabPageAdapterTest { ...@@ -225,11 +223,11 @@ public class NewTabPageAdapterTest {
RecordHistogram.disableForTests(); RecordHistogram.disableForTests();
RecordUserAction.disableForTests(); RecordUserAction.disableForTests();
@CategoryInt
final int category = KnownCategories.ARTICLES;
mSource = new FakeSuggestionsSource(); mSource = new FakeSuggestionsSource();
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.INITIALIZING); mSource.setStatusForCategory(category, CategoryStatus.INITIALIZING);
mSource.setInfoForCategory(KnownCategories.ARTICLES, mSource.setInfoForCategory(category, createInfo(category, false, true));
new SuggestionsCategoryInfo("Articles for you",
ContentSuggestionsCardLayout.FULL_CARD, false, true));
mAdapter = NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null); mAdapter = NewTabPageAdapter.create(new MockNewTabPageManager(mSource), null, null);
} }
...@@ -248,36 +246,20 @@ public class NewTabPageAdapterTest { ...@@ -248,36 +246,20 @@ public class NewTabPageAdapterTest {
@Feature({"Ntp"}) @Feature({"Ntp"})
public void testSuggestionLoading() { public void testSuggestionLoading() {
assertItemsFor(sectionWithStatusCard()); assertItemsFor(sectionWithStatusCard());
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mAdapter.getItemViewType(1));
assertEquals(NewTabPageItem.VIEW_TYPE_STATUS, mAdapter.getItemViewType(2));
assertEquals(NewTabPageItem.VIEW_TYPE_PROGRESS, mAdapter.getItemViewType(3));
assertEquals(NewTabPageItem.VIEW_TYPE_FOOTER, mAdapter.getItemViewType(4));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING, mAdapter.getItemViewType(5));
List<SnippetArticle> suggestions = createDummySuggestions(3); final int numSuggestions = 3;
List<SnippetArticle> suggestions = createDummySuggestions(numSuggestions);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE); mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions); mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
int numItems = mAdapter.getItemCount(); assertItemsFor(section(numSuggestions));
// From the loaded items, cut out aboveTheFold and header from the front,
// and footer and bottom spacer from the back.
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mAdapter.getItemViewType(1));
assertArticlesEqual(suggestions, 2, numItems - 2);
assertEquals(NewTabPageItem.VIEW_TYPE_FOOTER, mAdapter.getItemViewType(numItems - 2));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING, mAdapter.getItemViewType(numItems - 1));
// The adapter should ignore any new incoming data. // The adapter should ignore any new incoming data.
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, mSource.setSuggestionsForCategory(KnownCategories.ARTICLES,
Arrays.asList(new SnippetArticle[] {new SnippetArticle(0, "foo", "title1", "pub1", Arrays.asList(new SnippetArticle[] {new SnippetArticle(0, "foo", "title1", "pub1",
"txt1", "foo", "bar", 0, 0, 0, ContentSuggestionsCardLayout.FULL_CARD)})); "txt1", "foo", "bar", 0, 0, 0, ContentSuggestionsCardLayout.FULL_CARD)}));
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mAdapter.getItemViewType(1)); assertItemsFor(section(numSuggestions));
assertArticlesEqual(suggestions, 2, numItems - 2);
assertEquals(NewTabPageItem.VIEW_TYPE_FOOTER, mAdapter.getItemViewType(numItems - 2));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING, mAdapter.getItemViewType(numItems - 1));
} }
/** /**
...@@ -291,37 +273,20 @@ public class NewTabPageAdapterTest { ...@@ -291,37 +273,20 @@ public class NewTabPageAdapterTest {
mSource.setSuggestionsForCategory( mSource.setSuggestionsForCategory(
KnownCategories.ARTICLES, new ArrayList<SnippetArticle>()); KnownCategories.ARTICLES, new ArrayList<SnippetArticle>());
assertItemsFor(sectionWithStatusCard()); assertItemsFor(sectionWithStatusCard());
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mAdapter.getItemViewType(1));
assertEquals(NewTabPageItem.VIEW_TYPE_STATUS, mAdapter.getItemViewType(2));
assertEquals(NewTabPageItem.VIEW_TYPE_PROGRESS, mAdapter.getItemViewType(3));
assertEquals(NewTabPageItem.VIEW_TYPE_FOOTER, mAdapter.getItemViewType(4));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING, mAdapter.getItemViewType(5));
// We should load new suggestions when we get notified about them. // We should load new suggestions when we get notified about them.
List<SnippetArticle> suggestions = createDummySuggestions(5); final int numSuggestions = 5;
List<SnippetArticle> suggestions = createDummySuggestions(numSuggestions);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE); mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions); mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
int numItems = mAdapter.getItemCount(); assertItemsFor(section(numSuggestions));
// From the loaded items, cut out aboveTheFold and header from the front,
// and footer and bottom spacer from the back.
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mAdapter.getItemViewType(1));
assertArticlesEqual(suggestions, 2, numItems - 2);
assertEquals(NewTabPageItem.VIEW_TYPE_FOOTER, mAdapter.getItemViewType(numItems - 2));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING, mAdapter.getItemViewType(numItems - 1));
// The adapter should ignore any new incoming data. // The adapter should ignore any new incoming data.
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, mSource.setSuggestionsForCategory(KnownCategories.ARTICLES,
Arrays.asList(new SnippetArticle[] {new SnippetArticle(0, "foo", "title1", "pub1", Arrays.asList(new SnippetArticle[] {new SnippetArticle(0, "foo", "title1", "pub1",
"txt1", "foo", "bar", 0, 0, 0, ContentSuggestionsCardLayout.FULL_CARD)})); "txt1", "foo", "bar", 0, 0, 0, ContentSuggestionsCardLayout.FULL_CARD)}));
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mAdapter.getItemViewType(0)); assertItemsFor(section(numSuggestions));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mAdapter.getItemViewType(1));
assertArticlesEqual(suggestions, 2, numItems - 2);
assertEquals(NewTabPageItem.VIEW_TYPE_FOOTER, mAdapter.getItemViewType(numItems - 2));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING, mAdapter.getItemViewType(numItems - 1));
} }
/** /**
...@@ -472,6 +437,7 @@ public class NewTabPageAdapterTest { ...@@ -472,6 +437,7 @@ public class NewTabPageAdapterTest {
@Test @Test
@Feature({"Ntp"}) @Feature({"Ntp"})
public void testSectionVisibleIfEmpty() { public void testSectionVisibleIfEmpty() {
@CategoryInt
final int category = 42; final int category = 42;
final int sectionIdx = 1; // section 0 is the above-the-fold item, we test the one after. final int sectionIdx = 1; // section 0 is the above-the-fold item, we test the one after.
final List<SnippetArticle> articles = final List<SnippetArticle> articles =
...@@ -481,9 +447,7 @@ public class NewTabPageAdapterTest { ...@@ -481,9 +447,7 @@ public class NewTabPageAdapterTest {
// Part 1: VisibleIfEmpty = true // Part 1: VisibleIfEmpty = true
suggestionsSource = new FakeSuggestionsSource(); suggestionsSource = new FakeSuggestionsSource();
suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING); suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING);
suggestionsSource.setInfoForCategory( suggestionsSource.setInfoForCategory(category, createInfo(category, false, true));
category, new SuggestionsCategoryInfo(
"", ContentSuggestionsCardLayout.MINIMAL_CARD, false, true));
// 1.1 - Initial state // 1.1 - Initial state
mAdapter = mAdapter =
...@@ -507,9 +471,7 @@ public class NewTabPageAdapterTest { ...@@ -507,9 +471,7 @@ public class NewTabPageAdapterTest {
// Part 2: VisibleIfEmpty = false // Part 2: VisibleIfEmpty = false
suggestionsSource = new FakeSuggestionsSource(); suggestionsSource = new FakeSuggestionsSource();
suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING); suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING);
suggestionsSource.setInfoForCategory( suggestionsSource.setInfoForCategory(category, createInfo(category, false, false));
category, new SuggestionsCategoryInfo(
"", ContentSuggestionsCardLayout.MINIMAL_CARD, false, false));
// 2.1 - Initial state // 2.1 - Initial state
mAdapter = mAdapter =
...@@ -530,6 +492,7 @@ public class NewTabPageAdapterTest { ...@@ -530,6 +492,7 @@ public class NewTabPageAdapterTest {
@Test @Test
@Feature({"Ntp"}) @Feature({"Ntp"})
public void testMoreButton() { public void testMoreButton() {
@CategoryInt
final int category = 42; final int category = 42;
final int sectionIdx = 1; // section 0 is the above the fold, we test the one after. final int sectionIdx = 1; // section 0 is the above the fold, we test the one after.
final List<SnippetArticle> articles = final List<SnippetArticle> articles =
...@@ -540,9 +503,7 @@ public class NewTabPageAdapterTest { ...@@ -540,9 +503,7 @@ public class NewTabPageAdapterTest {
// Part 1: ShowMoreButton = true // Part 1: ShowMoreButton = true
suggestionsSource = new FakeSuggestionsSource(); suggestionsSource = new FakeSuggestionsSource();
suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING); suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING);
suggestionsSource.setInfoForCategory( suggestionsSource.setInfoForCategory(category, createInfo(category, true, true));
category, new SuggestionsCategoryInfo(
"", ContentSuggestionsCardLayout.MINIMAL_CARD, true, true));
// 1.1 - Initial state. // 1.1 - Initial state.
mAdapter = mAdapter =
...@@ -566,9 +527,7 @@ public class NewTabPageAdapterTest { ...@@ -566,9 +527,7 @@ public class NewTabPageAdapterTest {
// Part 1: ShowMoreButton = false // Part 1: ShowMoreButton = false
suggestionsSource = new FakeSuggestionsSource(); suggestionsSource = new FakeSuggestionsSource();
suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING); suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING);
suggestionsSource.setInfoForCategory( suggestionsSource.setInfoForCategory(category, createInfo(category, false, true));
category, new SuggestionsCategoryInfo(
"", ContentSuggestionsCardLayout.MINIMAL_CARD, false, true));
// 2.1 - Initial state. // 2.1 - Initial state.
mAdapter = mAdapter =
...@@ -627,9 +586,7 @@ public class NewTabPageAdapterTest { ...@@ -627,9 +586,7 @@ public class NewTabPageAdapterTest {
int dynamicCategory1 = 1010; int dynamicCategory1 = 1010;
List<SnippetArticle> dynamics1 = createDummySuggestions(5); List<SnippetArticle> dynamics1 = createDummySuggestions(5);
mSource.setInfoForCategory( mSource.setInfoForCategory(dynamicCategory1, createInfo(dynamicCategory1, true, false));
dynamicCategory1, new SuggestionsCategoryInfo("Dynamic 1",
ContentSuggestionsCardLayout.MINIMAL_CARD, true, false));
mSource.setStatusForCategory(dynamicCategory1, CategoryStatus.AVAILABLE); mSource.setStatusForCategory(dynamicCategory1, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(dynamicCategory1, dynamics1); mSource.setSuggestionsForCategory(dynamicCategory1, dynamics1);
mAdapter = mAdapter =
...@@ -638,9 +595,7 @@ public class NewTabPageAdapterTest { ...@@ -638,9 +595,7 @@ public class NewTabPageAdapterTest {
int dynamicCategory2 = 1011; int dynamicCategory2 = 1011;
List<SnippetArticle> dynamics2 = createDummySuggestions(11); List<SnippetArticle> dynamics2 = createDummySuggestions(11);
mSource.setInfoForCategory( mSource.setInfoForCategory(dynamicCategory2, createInfo(dynamicCategory1, false, false));
dynamicCategory2, new SuggestionsCategoryInfo("Dynamic 2",
ContentSuggestionsCardLayout.MINIMAL_CARD, false, false));
mSource.setStatusForCategory(dynamicCategory2, CategoryStatus.AVAILABLE); mSource.setStatusForCategory(dynamicCategory2, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(dynamicCategory2, dynamics2); mSource.setSuggestionsForCategory(dynamicCategory2, dynamics2);
mAdapter = mAdapter =
...@@ -757,6 +712,7 @@ public class NewTabPageAdapterTest { ...@@ -757,6 +712,7 @@ public class NewTabPageAdapterTest {
verify(adapter).notifyItemRemoved(2); verify(adapter).notifyItemRemoved(2);
verify(adapter).notifyItemInserted(2); verify(adapter).notifyItemInserted(2);
verify(adapter).notifyItemInserted(3); verify(adapter).notifyItemInserted(3);
verify(adapter).notifyItemInserted(4);
// Adapter content: // Adapter content:
// Idx | Item // Idx | Item
...@@ -764,16 +720,19 @@ public class NewTabPageAdapterTest { ...@@ -764,16 +720,19 @@ public class NewTabPageAdapterTest {
// 0 | Above-the-fold // 0 | Above-the-fold
// 1 | Header // 1 | Header
// 2 | Status // 2 | Status
// 3 | Progress Indicator // 3 | Action
// 4 | Footer // 4 | Progress Indicator
// 5 | Spacer // 5 | Footer
// 6 | Spacer
final int newSuggestionCount = 7; final int newSuggestionCount = 7;
final int changedCount = 3; // status, action and progress will be replaced by articles.
suggestionsSource.setSuggestionsForCategory( suggestionsSource.setSuggestionsForCategory(
KnownCategories.ARTICLES, createDummySuggestions(newSuggestionCount)); KnownCategories.ARTICLES, createDummySuggestions(newSuggestionCount));
adapter.onNewSuggestions(KnownCategories.ARTICLES); adapter.onNewSuggestions(KnownCategories.ARTICLES);
verify(adapter).notifyItemRangeChanged(2, 2); // status and progress replaced by articles. verify(adapter).notifyItemRangeChanged(2, changedCount);
verify(adapter).notifyItemRangeInserted(4, newSuggestionCount - 2); verify(adapter).notifyItemRangeInserted(
2 + changedCount, newSuggestionCount - changedCount);
// Adapter content: // Adapter content:
// Idx | Item // Idx | Item
...@@ -787,8 +746,8 @@ public class NewTabPageAdapterTest { ...@@ -787,8 +746,8 @@ public class NewTabPageAdapterTest {
suggestionsSource.setSuggestionsForCategory( suggestionsSource.setSuggestionsForCategory(
KnownCategories.ARTICLES, createDummySuggestions(0)); KnownCategories.ARTICLES, createDummySuggestions(0));
adapter.onCategoryStatusChanged(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT); adapter.onCategoryStatusChanged(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT);
verify(adapter, times(2)).notifyItemRangeChanged(2, 2); verify(adapter, times(2)).notifyItemRangeChanged(2, changedCount);
verify(adapter).notifyItemRangeRemoved(4, newSuggestionCount - 2); verify(adapter).notifyItemRangeRemoved(2 + changedCount, newSuggestionCount - changedCount);
} }
@Test @Test
...@@ -800,18 +759,19 @@ public class NewTabPageAdapterTest { ...@@ -800,18 +759,19 @@ public class NewTabPageAdapterTest {
NewTabPageAdapter adapter = NewTabPageAdapter.create(ntpManager, null, null); NewTabPageAdapter adapter = NewTabPageAdapter.create(ntpManager, null, null);
assertEquals(5, adapter.getGroups().size()); assertEquals(5, adapter.getGroups().size());
ItemGroup signinPromoGroup = adapter.getGroup(4); ItemGroup signinPromoGroup = adapter.getGroup(5);
// Adapter content: // Adapter content:
// Idx | Item // Idx | Item | Group Index
// ----|---------------- // ----|--------------------|-------------
// 0 | Above-the-fold // 0 | Above-the-fold | 0
// 1 | Header // 1 | Header | 1
// 2 | Status // 2 | Status | 1
// 3 | Progress Indicator // 3 | Action | 1
// 4 | Sign in promo // 4 | Progress Indicator | 1
// 5 | Footer // 5 | Sign in promo | 2
// 6 | Spacer // 6 | Footer | 3
// 7 | Spacer | 4
assertEquals(1, signinPromoGroup.getItems().size()); assertEquals(1, signinPromoGroup.getItems().size());
assertEquals(NewTabPageItem.VIEW_TYPE_PROMO, signinPromoGroup.getItems().get(0).getType()); assertEquals(NewTabPageItem.VIEW_TYPE_PROMO, signinPromoGroup.getItems().get(0).getType());
...@@ -832,9 +792,10 @@ public class NewTabPageAdapterTest { ...@@ -832,9 +792,10 @@ public class NewTabPageAdapterTest {
.setNewTabPageSigninPromoDismissed(false); .setNewTabPageSigninPromoDismissed(false);
MockNewTabPageManager ntpManager = new MockNewTabPageManager(mSource); MockNewTabPageManager ntpManager = new MockNewTabPageManager(mSource);
NewTabPageAdapter adapter = NewTabPageAdapter.create(ntpManager, null, null); NewTabPageAdapter adapter = NewTabPageAdapter.create(ntpManager, null, null);
final int signInPromoIndex = 5;
assertEquals(5, adapter.getGroups().size()); assertEquals(5, adapter.getGroups().size());
ItemGroup signinPromoGroup = adapter.getGroup(4); ItemGroup signinPromoGroup = adapter.getGroup(signInPromoIndex);
// Adapter content: // Adapter content:
// Idx | Item // Idx | Item
...@@ -842,14 +803,15 @@ public class NewTabPageAdapterTest { ...@@ -842,14 +803,15 @@ public class NewTabPageAdapterTest {
// 0 | Above-the-fold // 0 | Above-the-fold
// 1 | Header // 1 | Header
// 2 | Status // 2 | Status
// 3 | Progress Indicator // 3 | Action
// 4 | Sign in promo // 4 | Progress Indicator
// 5 | Footer // 5 | Sign in promo
// 6 | Spacer // 6 | Footer
// 7 | Spacer
assertEquals(NewTabPageItem.VIEW_TYPE_PROMO, signinPromoGroup.getItems().get(0).getType()); assertEquals(NewTabPageItem.VIEW_TYPE_PROMO, signinPromoGroup.getItems().get(0).getType());
adapter.dismissItem(4); adapter.dismissItem(signInPromoIndex);
assertTrue(signinPromoGroup.getItems().isEmpty()); assertTrue(signinPromoGroup.getItems().isEmpty());
assertTrue(ChromePreferenceManager.getInstance(RuntimeEnvironment.application) assertTrue(ChromePreferenceManager.getInstance(RuntimeEnvironment.application)
.getNewTabPageSigninPromoDismissed()); .getNewTabPageSigninPromoDismissed());
...@@ -857,7 +819,7 @@ public class NewTabPageAdapterTest { ...@@ -857,7 +819,7 @@ public class NewTabPageAdapterTest {
adapter = NewTabPageAdapter.create(ntpManager, null, null); adapter = NewTabPageAdapter.create(ntpManager, null, null);
assertEquals(5, adapter.getGroups().size()); assertEquals(5, adapter.getGroups().size());
// The items below the signin promo move up, footer is now at the position of the promo. // The items below the signin promo move up, footer is now at the position of the promo.
assertEquals(NewTabPageItem.VIEW_TYPE_FOOTER, adapter.getItemViewType(4)); assertEquals(NewTabPageItem.VIEW_TYPE_FOOTER, adapter.getItemViewType(signInPromoIndex));
} }
/** Registers the category with hasMoreButton=false and showIfEmpty=true*/ /** Registers the category with hasMoreButton=false and showIfEmpty=true*/
...@@ -867,9 +829,7 @@ public class NewTabPageAdapterTest { ...@@ -867,9 +829,7 @@ public class NewTabPageAdapterTest {
// AVAILABLE. // AVAILABLE.
suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABLE); suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABLE);
// Important: showIfEmpty flag to true. // Important: showIfEmpty flag to true.
suggestionsSource.setInfoForCategory( suggestionsSource.setInfoForCategory(category, createInfo(category, false, true));
category, new SuggestionsCategoryInfo(
"", ContentSuggestionsCardLayout.FULL_CARD, false, true));
suggestionsSource.setSuggestionsForCategory( suggestionsSource.setSuggestionsForCategory(
category, createDummySuggestions(suggestionCount)); category, createDummySuggestions(suggestionCount));
} }
...@@ -1038,11 +998,7 @@ public class NewTabPageAdapterTest { ...@@ -1038,11 +998,7 @@ public class NewTabPageAdapterTest {
@Override @Override
public void closeContextMenu() { public void closeContextMenu() {
throw new UnsupportedAddressTypeException(); throw new UnsupportedOperationException();
}
public void setSuggestionsSource(SuggestionsSource suggestionsSource) {
mSuggestionsSource = suggestionsSource;
} }
@Override @Override
......
...@@ -4,27 +4,28 @@ ...@@ -4,27 +4,28 @@
package org.chromium.chrome.browser.ntp.cards; package org.chromium.chrome.browser.ntp.cards;
import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createDummySuggestions;
import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createInfo;
import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createSection;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.any; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.anyInt; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createDummySuggestions;
import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createInfo;
import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsTestUtils.createSection;
import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
import org.chromium.chrome.browser.ntp.snippets.SnippetArticle; import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
import org.chromium.testing.local.LocalRobolectricTestRunner; import org.chromium.testing.local.LocalRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import java.util.List; import java.util.List;
...@@ -34,8 +35,10 @@ import java.util.List; ...@@ -34,8 +35,10 @@ import java.util.List;
@RunWith(LocalRobolectricTestRunner.class) @RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE) @Config(manifest = Config.NONE)
public class SuggestionsSectionTest { public class SuggestionsSectionTest {
/** Number of items in a section when there are no suggestions: header, status, progress. */ /**
private static final int EMPTY_SECTION_COUNT = 3; * Number of items in a section when there are no suggestions: header, status, action, progress.
*/
private static final int EMPTY_SECTION_COUNT = 4;
@Test @Test
@Feature({"Ntp"}) @Feature({"Ntp"})
...@@ -44,33 +47,19 @@ public class SuggestionsSectionTest { ...@@ -44,33 +47,19 @@ public class SuggestionsSectionTest {
List<SnippetArticle> snippets = createDummySuggestions(3); List<SnippetArticle> snippets = createDummySuggestions(3);
SuggestionsSection section; SuggestionsSection section;
// Part 1: ShowMoreButton = true. section = new SuggestionsSection(createInfo(42, true, true), observerMock);
section = new SuggestionsSection(42, createInfo(true, true), observerMock, null);
section.setStatus(CategoryStatus.AVAILABLE); section.setStatus(CategoryStatus.AVAILABLE);
assertNotNull(section.getActionItem()); assertNotNull(section.getActionItem());
// 1.1: Without snippets. // Without snippets.
assertEquals(-1, section.getDismissSiblingPosDelta(section.getActionItem())); assertEquals(-1, section.getDismissSiblingPosDelta(section.getActionItem()));
assertEquals(1, section.getDismissSiblingPosDelta(section.getStatusItem())); assertEquals(1, section.getDismissSiblingPosDelta(section.getStatusItem()));
// 1.2: With snippets. // With snippets.
section.setSuggestions(snippets, CategoryStatus.AVAILABLE); section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
assertEquals(0, section.getDismissSiblingPosDelta(section.getActionItem())); assertEquals(0, section.getDismissSiblingPosDelta(section.getActionItem()));
assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem())); assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
assertEquals(0, section.getDismissSiblingPosDelta(snippets.get(0))); assertEquals(0, section.getDismissSiblingPosDelta(snippets.get(0)));
// Part 2: ShowMoreButton = false.
section = new SuggestionsSection(42, createInfo(false, true), observerMock, null);
section.setStatus(CategoryStatus.AVAILABLE);
assertNull(section.getActionItem());
// 2.1: Without snippets.
assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
// 2.2: With snippets.
section.setSuggestions(snippets, CategoryStatus.AVAILABLE);
assertEquals(0, section.getDismissSiblingPosDelta(section.getStatusItem()));
assertEquals(0, section.getDismissSiblingPosDelta(snippets.get(0)));
} }
@Test @Test
...@@ -96,7 +85,6 @@ public class SuggestionsSectionTest { ...@@ -96,7 +85,6 @@ public class SuggestionsSectionTest {
@Feature({"Ntp"}) @Feature({"Ntp"})
public void testSetStatusNotification() { public void testSetStatusNotification() {
ItemGroup.Observer observerMock = mock(ItemGroup.Observer.class); ItemGroup.Observer observerMock = mock(ItemGroup.Observer.class);
final int emptySectionCount = 3;
final int suggestionCount = 5; final int suggestionCount = 5;
List<SnippetArticle> snippets = createDummySuggestions(suggestionCount); List<SnippetArticle> snippets = createDummySuggestions(suggestionCount);
......
...@@ -179,7 +179,7 @@ base::android::ScopedJavaLocalRef<jobject> NTPSnippetsBridge::GetCategoryInfo( ...@@ -179,7 +179,7 @@ base::android::ScopedJavaLocalRef<jobject> NTPSnippetsBridge::GetCategoryInfo(
if (!info) if (!info)
return base::android::ScopedJavaLocalRef<jobject>(env, nullptr); return base::android::ScopedJavaLocalRef<jobject>(env, nullptr);
return Java_SnippetsBridge_createSuggestionsCategoryInfo( return Java_SnippetsBridge_createSuggestionsCategoryInfo(
env, ConvertUTF16ToJavaString(env, info->title()), env, category, ConvertUTF16ToJavaString(env, info->title()),
static_cast<int>(info->card_layout()), info->has_more_button(), static_cast<int>(info->card_layout()), info->has_more_button(),
info->show_if_empty()); info->show_if_empty());
} }
......
...@@ -8,15 +8,12 @@ ...@@ -8,15 +8,12 @@
<message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get content suggestions on the New Tab Page." formatter_data="android_java"> <message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get content suggestions on the New Tab Page." formatter_data="android_java">
Get suggested content Get suggested content
</message> </message>
<message name="IDS_NTP_STATUS_CARD_TITLE_NO_BOOKMARKS" desc="On the New Tab Page, title of the status card explaining that there is no new content available in the bookmarks section." formatter_data="android_java"> <message name="IDS_NTP_STATUS_CARD_TITLE_NO_SUGGESTIONS" desc="On the New Tab Page, title of the status card explaining that there is no new content available in the section." formatter_data="android_java">
Done for now Done for now
</message> </message>
<message name="IDS_NTP_STATUS_CARD_NO_BOOKMARKS" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see bookmarks in this area in the future." formatter_data="android_java"> <message name="IDS_NTP_STATUS_CARD_NO_BOOKMARKS" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see bookmarks in this area in the future." formatter_data="android_java">
Your recently visited bookmarks will appear here. Your recently visited bookmarks will appear here.
</message> </message>
<message name="IDS_NTP_STATUS_CARD_TITLE_NO_ARTICLES" desc="On the New Tab Page, title of the status card explaining that there is no new content available in the articles section." formatter_data="android_java">
All Read
</message>
<message name="IDS_NTP_STATUS_CARD_NO_ARTICLES" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see suggested articles in this area in the future." formatter_data="android_java"> <message name="IDS_NTP_STATUS_CARD_NO_ARTICLES" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see suggested articles in this area in the future." formatter_data="android_java">
More articles will appear when the time is right. More articles will appear when the time is right.
</message> </message>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment