Commit 35978862 authored by mvanouwerkerk's avatar mvanouwerkerk Committed by Commit bot

Ntp: show footer with learn more link.

BUG=637257

Review-Url: https://codereview.chromium.org/2275693003
Cr-Commit-Position: refs/heads/master@{#414738}
parent 35a95ad0
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/snippets_text_color"
android:textSize="12sp"
android:textStyle="italic"
android:padding="12dp"
android:gravity="center" />
......@@ -5,7 +5,6 @@
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suggestions_section_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/snippets_list_header_text_color"
......
......@@ -249,6 +249,14 @@ public class NewTabPage
}
}
@Override
public void onLearnMoreClicked() {
if (mIsDestroyed) return;
// TODO(mvanouwerkerk): UMA logging.
String url = "https://support.google.com/chrome/?p=new_tab";
openUrl(WindowOpenDisposition.CURRENT_TAB, url);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private boolean switchToExistingTab(String url) {
String matchPattern = CommandLine.getInstance().getSwitchValue(
......
......@@ -258,6 +258,11 @@ public class NewTabPageView extends FrameLayout
* called whenever a ContextMenu is closed.
*/
void removeContextMenuCloseCallback(Callback<Menu> callback);
/**
* Handles clicks on the "learn more" link in the footer.
*/
void onLearnMoreClicked();
}
/**
......
......@@ -210,6 +210,7 @@ public class CardViewHolder extends NewTabPageViewHolder {
/**
* Override this to provide a context menu for the card. This method will not be called if the
* card is currently peeking.
* @param menu The menu to add menu items to.
*/
protected void createContextMenu(ContextMenu menu) {}
......@@ -291,6 +292,7 @@ public class CardViewHolder extends NewTabPageViewHolder {
case NewTabPageItem.VIEW_TYPE_HEADER:
case NewTabPageItem.VIEW_TYPE_SPACING:
case NewTabPageItem.VIEW_TYPE_PROGRESS:
case NewTabPageItem.VIEW_TYPE_FOOTER:
return false;
default:
assert false;
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.ntp.cards;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
import org.chromium.ui.text.NoUnderlineClickableSpan;
import org.chromium.ui.text.SpanApplier;
/**
* A footer to show some text and a link to learn more.
*/
public class Footer extends SingleItemGroup {
@Override
public int getType() {
return NewTabPageItem.VIEW_TYPE_FOOTER;
}
/**
* The {@code ViewHolder} for the {@link Footer}.
*/
public static class ViewHolder extends NewTabPageViewHolder {
public ViewHolder(ViewGroup root, final NewTabPageManager manager) {
super(LayoutInflater.from(root.getContext())
.inflate(R.layout.new_tab_page_footer, root, false));
NoUnderlineClickableSpan link = new NoUnderlineClickableSpan() {
@Override
public void onClick(View view) {
// TODO(mvanouwerkerk): Ensure this can be activated when using TalkBack.
manager.onLearnMoreClicked();
}
};
TextView textView = (TextView) itemView;
textView.setText(SpanApplier.applySpans(
root.getResources().getString(R.string.ntp_learn_more_about_suggested_content),
new SpanApplier.SpanInfo("<link>", "</link>", link)));
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
......@@ -59,6 +59,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder>
*/
private final List<ItemGroup> mGroups = new ArrayList<>();
private final AboveTheFoldItem mAboveTheFold = new AboveTheFoldItem();
private final Footer mFooter = new Footer();
private final SpacingItem mBottomSpacer = new SpacingItem();
/** Maps suggestion categories to sections, with stable iteration ordering. */
......@@ -266,6 +267,10 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder>
return new ActionItem.ViewHolder(mRecyclerView, mNewTabPageManager, mUiConfig);
}
if (viewType == NewTabPageItem.VIEW_TYPE_FOOTER) {
return new Footer.ViewHolder(mRecyclerView, mNewTabPageManager);
}
return null;
}
......@@ -299,10 +304,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder>
}
public int getLastContentItemPosition() {
// TODO(mvanouwerkerk): Don't rely on getBottomSpacerPosition() here.
int bottomSpacerPosition = getBottomSpacerPosition();
if (bottomSpacerPosition == RecyclerView.NO_POSITION) return RecyclerView.NO_POSITION;
return bottomSpacerPosition - 1;
return getGroupPositionOffset(mFooter);
}
public int getBottomSpacerPosition() {
......@@ -336,6 +338,7 @@ public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder>
// TODO(treib,bauerb): Preserve the order of categories we got from getCategories.
mGroups.addAll(mSections.values());
if (!mSections.isEmpty()) {
mGroups.add(mFooter);
mGroups.add(mBottomSpacer);
}
......
......@@ -64,6 +64,12 @@ public interface NewTabPageItem {
*/
public static final int VIEW_TYPE_ACTION = 7;
/**
* View type for a {@link Footer}.
* @see Adapter#getItemViewType(int)
*/
public static final int VIEW_TYPE_FOOTER = 8;
/**
* Returns the type ({@link ViewType}) of this list item. This is so we can
* distinguish between different elements that are held in a single RecyclerView holder.
......
......@@ -246,7 +246,7 @@ public class NewTabPageRecyclerView extends RecyclerView {
/**
* Finds the view holder for the first header.
* @return The {@link ViewHolder} of the header, or null if it is not present.
* @return The {@code ViewHolder} of the header, or null if it is not present.
*/
private SectionHeaderViewHolder findFirstHeader() {
ViewHolder viewHolder =
......@@ -258,7 +258,7 @@ public class NewTabPageRecyclerView extends RecyclerView {
/**
* Finds the view holder for the first card.
* @return The {@link ViewHolder} for the first card, or null if it is not present.
* @return The {@code ViewHolder} for the first card, or null if it is not present.
*/
private CardViewHolder findFirstCard() {
ViewHolder viewHolder =
......@@ -269,21 +269,20 @@ public class NewTabPageRecyclerView extends RecyclerView {
}
/**
* Finds the view holder for the last content item: a card or status indicator.
* @return The {@link ViewHolder} of the last content item, or null if it is not present.
* Finds the view holder for the last content item: the footer.
* @return The {@code ViewHolder} of the last content item, or null if it is not present.
*/
private ViewHolder findLastContentItem() {
ViewHolder viewHolder = findViewHolderForAdapterPosition(
getNewTabPageAdapter().getLastContentItemPosition());
if (viewHolder instanceof CardViewHolder) return viewHolder;
if (viewHolder instanceof ProgressViewHolder) return viewHolder;
if (viewHolder instanceof Footer.ViewHolder) return viewHolder;
return null;
}
/**
* Finds the view holder for the bottom spacer.
* @return The {@link ViewHolder} of the bottom spacer, or null if it is not present.
* @return The {@code ViewHolder} of the bottom spacer, or null if it is not present.
*/
private ViewHolder findBottomSpacer() {
return findViewHolderForAdapterPosition(getNewTabPageAdapter().getBottomSpacerPosition());
......
......@@ -23,7 +23,6 @@ public class SectionHeaderViewHolder extends NewTabPageViewHolder {
private final int mMaxSnippetHeaderHeight;
private final int mMaxPeekPadding;
private final TextView mHeaderTextView;
private final NewTabPageRecyclerView mRecyclerView;
private SectionHeader mHeaderListItem;
......@@ -37,7 +36,6 @@ public class SectionHeaderViewHolder extends NewTabPageViewHolder {
mMaxPeekPadding = itemView.getResources().getDimensionPixelSize(
R.dimen.snippets_padding_and_peeking_card_height);
mHeaderTextView = (TextView) itemView.findViewById(R.id.suggestions_section_header);
mRecyclerView = recyclerView;
MarginResizer.createWithViewAdapter(itemView, config);
}
......@@ -45,7 +43,7 @@ public class SectionHeaderViewHolder extends NewTabPageViewHolder {
@Override
public void onBindViewHolder(NewTabPageItem header) {
mHeaderListItem = (SectionHeader) header;
mHeaderTextView.setText(mHeaderListItem.getHeaderText());
((TextView) itemView).setText(mHeaderListItem.getHeaderText());
updateDisplay(0, false);
}
......
......@@ -1979,6 +1979,9 @@ To obtain new licenses, connect to the internet and play your downloaded content
<message name="IDS_ACCESSIBILITY_NTP_OFFLINE_BADGE" desc="Content description for the badge that indicates offline availability of a most visited item on the new tab page.">
Available offline
</message>
<message name="IDS_NTP_LEARN_MORE_ABOUT_SUGGESTED_CONTENT" desc="Text in the footer of the New Tab Page. Part of the text is a link to a help center page where the user can learn more about suggested content.">
<ph name="BEGIN_LINK">&lt;link&gt;</ph>Learn more<ph name="END_LINK">&lt;/link&gt;</ph> about suggested content
</message>
<!-- Toolbar button strings -->
<message name="IDS_OPEN_TABS" desc="Text for button to enter the tab switcher and show tabs that are open on this device">
......
......@@ -546,6 +546,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java",
"java/src/org/chromium/chrome/browser/ntp/cards/DisplayStyleObserverAdapter.java",
"java/src/org/chromium/chrome/browser/ntp/cards/ItemGroup.java",
"java/src/org/chromium/chrome/browser/ntp/cards/Footer.java",
"java/src/org/chromium/chrome/browser/ntp/cards/MarginResizer.java",
"java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java",
"java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageItem.java",
......
......@@ -332,5 +332,10 @@ public class ArticleSnippetsTest extends ChromeActivityTestCaseBase<ChromeActivi
public void removeContextMenuCloseCallback(Callback<Menu> callback) {
throw new UnsupportedOperationException();
}
@Override
public void onLearnMoreClicked() {
throw new UnsupportedOperationException();
}
}
}
......@@ -39,24 +39,24 @@ public class NewTabPageAdapterTest {
org.robolectric.shadows.ShadowLog.stream = System.out;
}
private FakeSuggestionsSource mSnippetsSource = new FakeSuggestionsSource();
private NewTabPageAdapter mNtpAdapter;
private FakeSuggestionsSource mSource;
private NewTabPageAdapter mAdapter;
/**
* Asserts that {@link #mNtpAdapter}.{@link NewTabPageAdapter#getItemCount()} corresponds to an
* Asserts that {@link #mAdapter}.{@link NewTabPageAdapter#getItemCount()} corresponds to an
* NTP with the given sections in it.
* @param sections A list of sections, each represented by the number of items that are required
* to represent it on the UI. For readability, these numbers should be generated
* to represent it in the UI. For readability, these numbers should be generated
* with the methods below.
*/
private void assertItemsFor(int... sections) {
int expectedCount = 1; // above-the-fold.
for (int section : sections) expectedCount += section;
if (sections.length > 0) expectedCount += 1; // bottom spacer.
int actualCount = mNtpAdapter.getItemCount();
if (sections.length > 0) expectedCount += 2; // footer and bottom spacer.
int actualCount = mAdapter.getItemCount();
assertEquals("Expected " + expectedCount + " items, but the following " + actualCount
+ " were present: " + mNtpAdapter.getItems(),
expectedCount, mNtpAdapter.getItemCount());
+ " were present: " + mAdapter.getItems(),
expectedCount, mAdapter.getItemCount());
}
/**
......@@ -94,14 +94,6 @@ public class NewTabPageAdapterTest {
return 3; // Header, status card and progress indicator.
}
/**
* To be used with {@link #assertItemsFor(int...)}, for a section that is hidden.
* @return The number of items that should be used by the adapter to represent this section.
*/
private int sectionHidden() {
return 0; // The section returns no items.
}
/**
* To be used with {@link #assertItemsFor(int...)}, for a section with button that has no
* suggestions and instead displays a status card.
......@@ -116,156 +108,153 @@ public class NewTabPageAdapterTest {
RecordHistogram.disableForTests();
RecordUserAction.disableForTests();
mSnippetsSource = new FakeSuggestionsSource();
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.INITIALIZING);
mSnippetsSource.setInfoForCategory(
KnownCategories.ARTICLES,
new SuggestionsCategoryInfo(
"Articles for you", ContentSuggestionsCardLayout.FULL_CARD, false, true));
mNtpAdapter = new NewTabPageAdapter(null, null, mSnippetsSource, null);
mSource = new FakeSuggestionsSource();
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.INITIALIZING);
mSource.setInfoForCategory(KnownCategories.ARTICLES,
new SuggestionsCategoryInfo("Articles for you",
ContentSuggestionsCardLayout.FULL_CARD, false, true));
mAdapter = new NewTabPageAdapter(null, null, mSource, null);
}
/**
* Tests the content of the adapter under standard conditions: on start and after a snippet
* Tests the content of the adapter under standard conditions: on start and after a suggestions
* fetch.
*/
@Test
@Feature({"Ntp"})
public void testSnippetLoading() {
public void testSuggestionLoading() {
assertItemsFor(sectionWithStatusCard());
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mNtpAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mNtpAdapter.getItemViewType(1));
assertEquals(NewTabPageItem.VIEW_TYPE_STATUS, mNtpAdapter.getItemViewType(2));
assertEquals(NewTabPageItem.VIEW_TYPE_PROGRESS, mNtpAdapter.getItemViewType(3));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING, mNtpAdapter.getItemViewType(4));
List<SnippetArticle> snippets = createDummySnippets(3);
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
List<NewTabPageItem> loadedItems = new ArrayList<>(mNtpAdapter.getItems());
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mNtpAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mNtpAdapter.getItemViewType(1));
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);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
List<NewTabPageItem> loadedItems = new ArrayList<>(mAdapter.getItems());
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mAdapter.getItemViewType(1));
// From the loadedItems, cut out aboveTheFold and header from the front,
// and bottom spacer from the back.
assertEquals(snippets, loadedItems.subList(2, loadedItems.size() - 1));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING,
mNtpAdapter.getItemViewType(loadedItems.size() - 1));
// and footer and bottom spacer from the back.
assertEquals(suggestions, loadedItems.subList(2, loadedItems.size() - 2));
assertEquals(
NewTabPageItem.VIEW_TYPE_FOOTER, mAdapter.getItemViewType(loadedItems.size() - 2));
assertEquals(
NewTabPageItem.VIEW_TYPE_SPACING, mAdapter.getItemViewType(loadedItems.size() - 1));
// The adapter should ignore any new incoming data.
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES,
Arrays.asList(new SnippetArticle[] {new SnippetArticle(
0, "foo", "title1", "pub1", "txt1", "foo", "bar", 0, 0, 0,
ContentSuggestionsCardLayout.FULL_CARD)}));
assertEquals(loadedItems, mNtpAdapter.getItems());
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES,
Arrays.asList(new SnippetArticle[] {new SnippetArticle(0, "foo", "title1", "pub1",
"txt1", "foo", "bar", 0, 0, 0, ContentSuggestionsCardLayout.FULL_CARD)}));
assertEquals(loadedItems, mAdapter.getItems());
}
/**
* Tests that the adapter keeps listening for snippet updates if it didn't get anything from
* Tests that the adapter keeps listening for suggestion updates if it didn't get anything from
* a previous fetch.
*/
@Test
@Feature({"Ntp"})
public void testSnippetLoadingInitiallyEmpty() {
public void testSuggestionLoadingInitiallyEmpty() {
// If we don't get anything, we should be in the same situation as the initial one.
mSnippetsSource.setSuggestionsForCategory(
mSource.setSuggestionsForCategory(
KnownCategories.ARTICLES, new ArrayList<SnippetArticle>());
assertItemsFor(sectionWithStatusCard());
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mNtpAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mNtpAdapter.getItemViewType(1));
assertEquals(NewTabPageItem.VIEW_TYPE_STATUS, mNtpAdapter.getItemViewType(2));
assertEquals(NewTabPageItem.VIEW_TYPE_PROGRESS, mNtpAdapter.getItemViewType(3));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING, mNtpAdapter.getItemViewType(4));
// We should load new snippets when we get notified about them.
List<SnippetArticle> snippets = createDummySnippets(5);
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
List<NewTabPageItem> loadedItems = new ArrayList<>(mNtpAdapter.getItems());
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mNtpAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mNtpAdapter.getItemViewType(1));
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.
List<SnippetArticle> suggestions = createDummySuggestions(5);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
List<NewTabPageItem> loadedItems = new ArrayList<>(mAdapter.getItems());
assertEquals(NewTabPageItem.VIEW_TYPE_ABOVE_THE_FOLD, mAdapter.getItemViewType(0));
assertEquals(NewTabPageItem.VIEW_TYPE_HEADER, mAdapter.getItemViewType(1));
// From the loadedItems, cut out aboveTheFold and header from the front,
// and bottom spacer from the back.
assertEquals(snippets, loadedItems.subList(2, loadedItems.size() - 1));
assertEquals(NewTabPageItem.VIEW_TYPE_SPACING,
mNtpAdapter.getItemViewType(loadedItems.size() - 1));
// and footer and bottom spacer from the back.
assertEquals(suggestions, loadedItems.subList(2, loadedItems.size() - 2));
assertEquals(
NewTabPageItem.VIEW_TYPE_FOOTER, mAdapter.getItemViewType(loadedItems.size() - 2));
assertEquals(
NewTabPageItem.VIEW_TYPE_SPACING, mAdapter.getItemViewType(loadedItems.size() - 1));
// The adapter should ignore any new incoming data.
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES,
Arrays.asList(new SnippetArticle[] {new SnippetArticle(
0, "foo", "title1", "pub1", "txt1", "foo", "bar", 0, 0, 0,
ContentSuggestionsCardLayout.FULL_CARD)}));
assertEquals(loadedItems, mNtpAdapter.getItems());
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES,
Arrays.asList(new SnippetArticle[] {new SnippetArticle(0, "foo", "title1", "pub1",
"txt1", "foo", "bar", 0, 0, 0, ContentSuggestionsCardLayout.FULL_CARD)}));
assertEquals(loadedItems, mAdapter.getItems());
}
/**
* Tests that the adapter clears the snippets when asked to.
* Tests that the adapter clears the suggestions when asked to.
*/
@Test
@Feature({"Ntp"})
public void testSnippetClearing() {
List<SnippetArticle> snippets = createDummySnippets(4);
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
public void testSuggestionClearing() {
List<SnippetArticle> suggestions = createDummySuggestions(4);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
assertItemsFor(section(4));
// If we get told that snippets are enabled, we just leave the current
// ones there and not clear.
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.AVAILABLE);
// If we get told that the category is enabled, we just leave the current suggestions do not
// clear them.
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
assertItemsFor(section(4));
// When snippets are disabled, we clear them and we should go back to
// When the category is disabled, the suggestions are cleared and we should go back to
// the situation with the status card.
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.SIGNED_OUT);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT);
assertItemsFor(sectionWithStatusCard());
// The adapter should now be waiting for new snippets.
snippets = createDummySnippets(6);
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
// The adapter should now be waiting for new suggestions.
suggestions = createDummySuggestions(6);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
assertItemsFor(section(6));
}
/**
* Tests that the adapter loads snippets only when the status is favorable.
* Tests that the adapter loads suggestions only when the status is favorable.
*/
@Test
@Feature({"Ntp"})
public void testSnippetLoadingBlock() {
List<SnippetArticle> snippets = createDummySnippets(3);
public void testSuggestionLoadingBlock() {
List<SnippetArticle> suggestions = createDummySuggestions(3);
// By default, status is INITIALIZING, so we can load snippets
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
// By default, status is INITIALIZING, so we can load suggestions.
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
assertItemsFor(section(3));
// If we have snippets, we should not load the new list (i.e. the extra item does *not*
// appear).
snippets.add(new SnippetArticle(0, "https://site.com/url1", "title1", "pub1", "txt1",
suggestions.add(new SnippetArticle(0, "https://site.com/url1", "title1", "pub1", "txt1",
"https://site.com/url1", "https://amp.site.com/url1", 0, 0, 0,
ContentSuggestionsCardLayout.FULL_CARD));
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
assertItemsFor(section(3));
// When snippets are disabled, we should not be able to load them.
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.SIGNED_OUT);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
assertItemsFor(sectionWithStatusCard());
// INITIALIZING lets us load snippets still.
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.INITIALIZING);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.INITIALIZING);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
assertItemsFor(sectionWithStatusCard());
// The adapter should now be waiting for new snippets and the fourth one should appear.
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, suggestions);
assertItemsFor(section(4));
}
......@@ -275,23 +264,19 @@ public class NewTabPageAdapterTest {
@Test
@Feature({"Ntp"})
public void testProgressIndicatorDisplay() {
int progressPos = mNtpAdapter.getBottomSpacerPosition() - 1;
ProgressItem progress = (ProgressItem) mNtpAdapter.getItems().get(progressPos);
int progressPos = mAdapter.getLastContentItemPosition() - 1;
ProgressItem progress = (ProgressItem) mAdapter.getItems().get(progressPos);
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.INITIALIZING);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.INITIALIZING);
assertTrue(progress.isVisible());
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.AVAILABLE);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
assertFalse(progress.isVisible());
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.AVAILABLE_LOADING);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE_LOADING);
assertTrue(progress.isVisible());
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.SIGNED_OUT);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT);
assertFalse(progress.isVisible());
}
......@@ -302,31 +287,30 @@ public class NewTabPageAdapterTest {
@Test
@Feature({"Ntp"})
public void testSectionClearingWhenUnavailable() {
List<SnippetArticle> snippets = createDummySnippets(5);
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
List<SnippetArticle> snippets = createDummySuggestions(5);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
assertItemsFor(section(5));
// When the category goes away with a hard error, the section is cleared from the UI.
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES,
CategoryStatus.LOADING_ERROR);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.LOADING_ERROR);
assertItemsFor();
// Same when loading a new NTP.
mNtpAdapter = new NewTabPageAdapter(null, null, mSnippetsSource, null);
mAdapter = new NewTabPageAdapter(null, null, mSource, null);
assertItemsFor();
// Same for CATEGORY_EXPLICITLY_DISABLED.
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
mNtpAdapter = new NewTabPageAdapter(null, null, mSnippetsSource, null);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
mAdapter = new NewTabPageAdapter(null, null, mSource, null);
assertItemsFor(section(5));
mSnippetsSource.setStatusForCategory(
mSource.setStatusForCategory(
KnownCategories.ARTICLES, CategoryStatus.CATEGORY_EXPLICITLY_DISABLED);
assertItemsFor();
// Same when loading a new NTP.
mNtpAdapter = new NewTabPageAdapter(null, null, mSnippetsSource, null);
mAdapter = new NewTabPageAdapter(null, null, mSource, null);
assertItemsFor();
}
......@@ -336,18 +320,18 @@ public class NewTabPageAdapterTest {
@Test
@Feature({"Ntp"})
public void testUIUntouchedWhenNotProvided() {
List<SnippetArticle> snippets = createDummySnippets(4);
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
List<SnippetArticle> snippets = createDummySuggestions(4);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets);
assertItemsFor(section(4));
// When the category switches to NOT_PROVIDED, UI stays the same.
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.NOT_PROVIDED);
mSnippetsSource.silentlyRemoveCategory(KnownCategories.ARTICLES);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.NOT_PROVIDED);
mSource.silentlyRemoveCategory(KnownCategories.ARTICLES);
assertItemsFor(section(4));
// But it disappears when loading a new NTP.
mNtpAdapter = new NewTabPageAdapter(null, null, mSnippetsSource, null);
mAdapter = new NewTabPageAdapter(null, null, mSource, null);
assertItemsFor();
}
......@@ -356,7 +340,8 @@ public class NewTabPageAdapterTest {
public void testSectionVisibleIfEmpty() {
final int category = 42;
final int sectionIdx = 1; // section 0 is the above-the-fold item, we test the one after.
final List<SnippetArticle> articles = Collections.unmodifiableList(createDummySnippets(3));
final List<SnippetArticle> articles =
Collections.unmodifiableList(createDummySuggestions(3));
FakeSuggestionsSource suggestionsSource;
SuggestionsSection section;
......@@ -368,7 +353,7 @@ public class NewTabPageAdapterTest {
"", ContentSuggestionsCardLayout.MINIMAL_CARD, false, true));
// 1.1 - Initial state
mNtpAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
mAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
assertItemsFor(sectionWithStatusCard());
// 1.2 - With suggestions
......@@ -377,8 +362,8 @@ public class NewTabPageAdapterTest {
assertItemsFor(section(3));
// 1.3 - When all suggestions are dismissed
assertEquals(SuggestionsSection.class, mNtpAdapter.getGroups().get(sectionIdx).getClass());
section = (SuggestionsSection) mNtpAdapter.getGroups().get(sectionIdx);
assertEquals(SuggestionsSection.class, mAdapter.getGroups().get(sectionIdx).getClass());
section = (SuggestionsSection) mAdapter.getGroups().get(sectionIdx);
assertEquals(section(3), section.getItems().size());
section.removeSuggestion(articles.get(0));
section.removeSuggestion(articles.get(1));
......@@ -393,7 +378,7 @@ public class NewTabPageAdapterTest {
"", ContentSuggestionsCardLayout.MINIMAL_CARD, false, false));
// 2.1 - Initial state
mNtpAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
mAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
assertItemsFor();
// 2.2 - With suggestions
......@@ -412,7 +397,8 @@ public class NewTabPageAdapterTest {
public void testMoreButton() {
final int category = 42;
final int sectionIdx = 1; // section 0 is the above the fold, we test the one after.
final List<SnippetArticle> articles = Collections.unmodifiableList(createDummySnippets(3));
final List<SnippetArticle> articles =
Collections.unmodifiableList(createDummySuggestions(3));
FakeSuggestionsSource suggestionsSource;
SuggestionsSection section;
......@@ -424,7 +410,7 @@ public class NewTabPageAdapterTest {
"", ContentSuggestionsCardLayout.MINIMAL_CARD, true, true));
// 1.1 - Initial state.
mNtpAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
mAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
assertItemsFor(sectionWithStatusCardAndMoreButton());
// 1.2 - With suggestions.
......@@ -433,8 +419,8 @@ public class NewTabPageAdapterTest {
assertItemsFor(sectionWithMoreButton(3));
// 1.3 - When all suggestions are dismissed.
assertEquals(SuggestionsSection.class, mNtpAdapter.getGroups().get(sectionIdx).getClass());
section = (SuggestionsSection) mNtpAdapter.getGroups().get(sectionIdx);
assertEquals(SuggestionsSection.class, mAdapter.getGroups().get(sectionIdx).getClass());
section = (SuggestionsSection) mAdapter.getGroups().get(sectionIdx);
assertEquals(sectionWithMoreButton(3), section.getItems().size());
section.removeSuggestion(articles.get(0));
section.removeSuggestion(articles.get(1));
......@@ -449,7 +435,7 @@ public class NewTabPageAdapterTest {
"", ContentSuggestionsCardLayout.MINIMAL_CARD, false, true));
// 2.1 - Initial state.
mNtpAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
mAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
assertItemsFor(sectionWithStatusCard());
// 2.2 - With suggestions.
......@@ -458,8 +444,8 @@ public class NewTabPageAdapterTest {
assertItemsFor(section(3));
// 2.3 - When all suggestions are dismissed.
assertEquals(SuggestionsSection.class, mNtpAdapter.getGroups().get(sectionIdx).getClass());
section = (SuggestionsSection) mNtpAdapter.getGroups().get(sectionIdx);
assertEquals(SuggestionsSection.class, mAdapter.getGroups().get(sectionIdx).getClass());
section = (SuggestionsSection) mAdapter.getGroups().get(sectionIdx);
assertEquals(section(3), section.getItems().size());
section.removeSuggestion(articles.get(0));
section.removeSuggestion(articles.get(1));
......@@ -473,15 +459,15 @@ public class NewTabPageAdapterTest {
@Test
@Feature({"Ntp"})
public void testSuggestionInvalidated() {
List<SnippetArticle> articles = createDummySnippets(3);
mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, articles);
List<SnippetArticle> articles = createDummySuggestions(3);
mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE);
mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, articles);
assertItemsFor(section(3));
assertEquals(articles, mNtpAdapter.getItems().subList(2, 5));
assertEquals(articles, mAdapter.getItems().subList(2, 5));
SnippetArticle removed = articles.remove(1);
mSnippetsSource.fireSuggestionInvalidated(KnownCategories.ARTICLES, removed.mId);
assertEquals(articles, mNtpAdapter.getItems().subList(2, 4));
mSource.fireSuggestionInvalidated(KnownCategories.ARTICLES, removed.mId);
assertEquals(articles, mAdapter.getItems().subList(2, 4));
}
/**
......@@ -499,7 +485,7 @@ public class NewTabPageAdapterTest {
NewTabPageAdapter ntpAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
List<ItemGroup> groups = ntpAdapter.getGroups();
assertEquals(6, groups.size());
assertEquals(7, groups.size());
assertEquals(AboveTheFoldItem.class, groups.get(0).getClass());
assertEquals(SuggestionsSection.class, groups.get(1).getClass());
assertEquals(KnownCategories.ARTICLES, getCategory(groups.get(1)));
......@@ -520,7 +506,7 @@ public class NewTabPageAdapterTest {
ntpAdapter = new NewTabPageAdapter(null, null, suggestionsSource, null);
groups = ntpAdapter.getGroups();
assertEquals(6, groups.size());
assertEquals(7, groups.size());
assertEquals(AboveTheFoldItem.class, groups.get(0).getClass());
assertEquals(SuggestionsSection.class, groups.get(1).getClass());
assertEquals(KnownCategories.ARTICLES, getCategory(groups.get(1)));
......@@ -545,7 +531,7 @@ public class NewTabPageAdapterTest {
groups = ntpAdapter.getGroups();
assertEquals(5, groups.size());
assertEquals(6, groups.size());
assertEquals(AboveTheFoldItem.class, groups.get(0).getClass());
assertEquals(SuggestionsSection.class, groups.get(1).getClass());
assertEquals(KnownCategories.ARTICLES, getCategory(groups.get(1)));
......@@ -555,27 +541,29 @@ public class NewTabPageAdapterTest {
assertEquals(KnownCategories.DOWNLOADS, getCategory(groups.get(3)));
}
private List<SnippetArticle> createDummySnippets(int count) {
List<SnippetArticle> snippets = new ArrayList<>();
private List<SnippetArticle> createDummySuggestions(int count) {
List<SnippetArticle> suggestions = new ArrayList<>();
for (int index = 0; index < count; index++) {
snippets.add(new SnippetArticle(0, "https://site.com/url" + index, "title" + index,
suggestions.add(new SnippetArticle(0, "https://site.com/url" + index, "title" + index,
"pub" + index, "txt" + index, "https://site.com/url" + index,
"https://amp.site.com/url" + index, 0, 0, 0,
ContentSuggestionsCardLayout.FULL_CARD));
}
return snippets;
return suggestions;
}
/** Registers the category with hasMoreButton=false and showIfEmpty=true*/
private void registerCategory(FakeSuggestionsSource suggestionsSource,
@CategoryInt int category, int suggestionCount) {
// FakeSuggestionSource does not provide snippets if the category's status is not available.
// FakeSuggestionSource does not provide suggestions if the category's status is not
// AVAILABLE.
suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABLE);
// Important: showIfEmpty flag to true.
suggestionsSource.setInfoForCategory(
category, new SuggestionsCategoryInfo(
"", ContentSuggestionsCardLayout.FULL_CARD, false, true));
suggestionsSource.setSuggestionsForCategory(category, createDummySnippets(suggestionCount));
suggestionsSource.setSuggestionsForCategory(
category, createDummySuggestions(suggestionCount));
}
private int getCategory(ItemGroup itemGroup) {
......
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