Commit 0a673c39 authored by Xing Liu's avatar Xing Liu Committed by Chromium LUCI CQ

Read later: Add FRE text in bottom sheet.

Add "New" text through IPH system to provide FRE for reading list.

Bug: 1151567
Change-Id: I62534a77be3b3ac931c2e5cdf53028480dd1795f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2597814Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Commit-Queue: Xing Liu <xingliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841316}
parent 9f37bbef
......@@ -5,6 +5,10 @@
package org.chromium.chrome.browser.bookmarks.bottomsheet;
import android.content.Context;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.SuperscriptSpan;
import android.view.LayoutInflater;
import android.view.View;
......@@ -15,22 +19,29 @@ import androidx.core.util.Pair;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.Callback;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
import org.chromium.chrome.browser.bookmarks.BookmarkModel;
import org.chromium.chrome.browser.bookmarks.BookmarkUtils;
import org.chromium.chrome.browser.bookmarks.bottomsheet.BookmarkBottomSheetItemProperties.ItemType;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.bookmarks.BookmarkId;
import org.chromium.components.bookmarks.BookmarkType;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
import org.chromium.components.feature_engagement.FeatureConstants;
import org.chromium.components.feature_engagement.Tracker;
import org.chromium.ui.modelutil.LayoutViewBuilder;
import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter;
import org.chromium.ui.text.SpanApplier;
import org.chromium.ui.text.SpanApplier.SpanInfo;
import java.util.List;
......@@ -110,7 +121,7 @@ public class BookmarkBottomSheetCoordinator {
int type = bookmarkItem.getId().getType();
PropertyModel model =
new PropertyModel.Builder(BookmarkBottomSheetItemProperties.ALL_KEYS)
.with(BookmarkBottomSheetItemProperties.TITLE, bookmarkItem.getTitle())
.with(BookmarkBottomSheetItemProperties.TITLE, getTitle(bookmarkItem))
.with(BookmarkBottomSheetItemProperties.SUBTITLE, getSubtitle(bookmarkItem))
.with(BookmarkBottomSheetItemProperties.ICON_DRAWABLE_AND_COLOR,
new Pair<>(BookmarkUtils.getFolderIcon(mContext, type),
......@@ -121,7 +132,36 @@ public class BookmarkBottomSheetCoordinator {
return model;
}
private @Nullable String getSubtitle(@NonNull final BookmarkItem bookmarkItem) {
private CharSequence getTitle(@NonNull final BookmarkItem bookmarkItem) {
if (bookmarkItem.getId().getType() == BookmarkType.READING_LIST) {
Tracker tracker =
TrackerFactory.getTrackerForProfile(Profile.getLastUsedRegularProfile());
boolean showNew = tracker.isInitialized()
&& tracker.shouldTriggerHelpUI(
FeatureConstants.READ_LATER_BOTTOM_SHEET_FEATURE);
SpannableString spannableString = new SpannableString(
mContext.getResources().getString(R.string.reading_list_title_new));
// Maybe show a "New" text after the reading list title.
if (showNew) {
tracker.dismissed(FeatureConstants.READ_LATER_BOTTOM_SHEET_FEATURE);
spannableString = SpanApplier.applySpans(spannableString.toString(),
new SpanInfo("<new>", "</new>", new RelativeSizeSpan(0.75f),
new SuperscriptSpan(),
new ForegroundColorSpan(
ApiCompatibilityUtils.getColor(mContext.getResources(),
R.color.default_text_color_blue))));
} else {
spannableString = new SpannableString(SpanApplier.removeSpanText(
spannableString.toString(), new SpanInfo("<new>", "</new>")));
}
return spannableString;
}
return bookmarkItem.getTitle();
}
private @Nullable CharSequence getSubtitle(@NonNull final BookmarkItem bookmarkItem) {
switch (bookmarkItem.getId().getType()) {
case BookmarkType.NORMAL:
int totalCount = mBookmarkModel.getTotalBookmarkCount(bookmarkItem.getId());
......
......@@ -33,11 +33,11 @@ class BookmarkBottomSheetFolderRow extends BookmarkRow {
super(context, attrs);
}
void setTitle(@NonNull String title) {
void setTitle(@NonNull CharSequence title) {
mTitleView.setText(title);
}
void setSubtitle(@Nullable String subtitle) {
void setSubtitle(@Nullable CharSequence subtitle) {
mDescriptionView.setText(subtitle == null ? "" : subtitle);
}
......
......@@ -32,13 +32,13 @@ class BookmarkBottomSheetItemProperties {
/**
* The title of the bottom sheet item. e.g. Mobile bookmarks, reading list.
*/
static final PropertyModel.ReadableObjectPropertyKey<String> TITLE =
static final PropertyModel.ReadableObjectPropertyKey<CharSequence> TITLE =
new PropertyModel.ReadableObjectPropertyKey<>();
/**
* The subtitle of the bottom sheet item. e.g. 4 bookmarks, 8 unread pages.
*/
static final PropertyModel.ReadableObjectPropertyKey<String> SUBTITLE =
static final PropertyModel.ReadableObjectPropertyKey<CharSequence> SUBTITLE =
new PropertyModel.ReadableObjectPropertyKey<>();
/**
......
......@@ -1706,7 +1706,7 @@ public class BookmarkTest {
mActivityTestRule.getActivity(), R.id.bookmark_this_page_id);
// Click the reading list folder in the bottom sheet, and wait for reading list item added.
onView(withText("Reading list")).check(matches(isDisplayed())).perform(click());
onView(withText("Reading list ")).check(matches(isDisplayed())).perform(click());
CriteriaHelper.pollUiThread(() -> mBookmarkModel.getReadingListItem(mTestPage) != null);
TestThreadUtils.runOnUiThreadBlocking(() -> {
......
......@@ -11,6 +11,10 @@ import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.mockito.Mockito.when;
import static org.chromium.components.feature_engagement.FeatureConstants.READ_LATER_BOTTOM_SHEET_FEATURE;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
......@@ -22,6 +26,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
......@@ -30,6 +35,7 @@ import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
import org.chromium.chrome.browser.bookmarks.BookmarkModel;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.profiles.Profile;
......@@ -41,6 +47,7 @@ import org.chromium.components.bookmarks.BookmarkType;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
import org.chromium.components.feature_engagement.Tracker;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.util.ArrayList;
......@@ -60,19 +67,27 @@ public class BookmarkBottomSheetTest {
private static final String TITLE = "bookmark title";
private static final String TEST_URL_A = "http://a.com";
private static final String TEST_URL_B = "http://b.com";
private static final String READING_LIST_TITLE = "Reading list ";
private static final String READING_LIST_TITLE_NEW = "Reading list New";
private BookmarkBottomSheetCoordinator mBottomSheetCoordinator;
private BottomSheetController mBottomSheetController;
private BookmarkModel mBookmarkModel;
private BookmarkItem mItemClicked;
private boolean mCallbackInvoked;
@Mock
private Tracker mTracker;
@Before
public void setUp() {
when(mTracker.isInitialized()).thenReturn(true);
when(mTracker.shouldTriggerHelpUI(READ_LATER_BOTTOM_SHEET_FEATURE)).thenReturn(false);
mActivityTestRule.startMainActivityOnBlankPage();
TestThreadUtils.runOnUiThreadBlocking(() -> {
mBookmarkModel = new BookmarkModel(Profile.fromWebContents(
mActivityTestRule.getActivity().getActivityTab().getWebContents()));
TrackerFactory.setTrackerForTests(mTracker);
});
mBottomSheetController = mActivityTestRule.getActivity()
......@@ -88,6 +103,11 @@ public class BookmarkBottomSheetTest {
mItemClicked = null;
}
private void setShouldShowNew(boolean shouldShowNew) {
when(mTracker.shouldTriggerHelpUI(READ_LATER_BOTTOM_SHEET_FEATURE))
.thenReturn(shouldShowNew);
}
private void bottomSheetCallback(BookmarkItem item) {
mItemClicked = item;
mCallbackInvoked = true;
......@@ -144,7 +164,7 @@ public class BookmarkBottomSheetTest {
public void testBottomSheetShowWithoutBookmarks() throws InterruptedException {
showBottomSheet();
onView(withId(R.id.sheet_title)).check(matches(isDisplayed()));
onView(withText("Reading list")).check(matches(isDisplayed()));
onView(withText(READING_LIST_TITLE)).check(matches(isDisplayed()));
assertViewHolderHasString(0, "Save this page for later and get a reminder");
assertNoOverflowMenu(0, "No overflow menu for reading list folder.");
......@@ -153,6 +173,14 @@ public class BookmarkBottomSheetTest {
assertNoOverflowMenu(1, "No overflow menu for mobile bookmark folder.");
}
@Test
@MediumTest
public void testBottomSheetNewIPH() {
setShouldShowNew(true);
showBottomSheet();
onView(withText(READING_LIST_TITLE_NEW)).check(matches(isDisplayed()));
}
@Test
@MediumTest
public void testBottomSheetShowWithOneBookmark() {
......@@ -163,7 +191,7 @@ public class BookmarkBottomSheetTest {
});
showBottomSheet();
onView(withText("Reading list")).check(matches(isDisplayed()));
onView(withText(READING_LIST_TITLE)).check(matches(isDisplayed()));
assertViewHolderHasString(0, "1 unread page");
onView(withText("Mobile bookmarks")).check(matches(isDisplayed()));
......@@ -182,7 +210,7 @@ public class BookmarkBottomSheetTest {
});
showBottomSheet();
onView(withText("Reading list")).check(matches(isDisplayed()));
onView(withText(READING_LIST_TITLE)).check(matches(isDisplayed()));
assertViewHolderHasString(0, "2 unread pages");
onView(withText("Mobile bookmarks")).check(matches(isDisplayed()));
......@@ -194,7 +222,7 @@ public class BookmarkBottomSheetTest {
public void testBottomSheetClickThrough() {
showBottomSheet();
onView(withText("Mobile bookmarks")).check(matches(isDisplayed()));
onView(withText("Reading list")).check(matches(isDisplayed())).perform(click());
onView(withText(READING_LIST_TITLE)).check(matches(isDisplayed())).perform(click());
waitForBookmarkClicked();
Assert.assertEquals(BookmarkType.READING_LIST, mItemClicked.getId().getType());
......@@ -205,7 +233,7 @@ public class BookmarkBottomSheetTest {
@MediumTest
public void testBottomSheetCloseInvokeCallback() {
showBottomSheet();
onView(withText("Reading list")).check(matches(isDisplayed()));
onView(withText(READING_LIST_TITLE)).check(matches(isDisplayed()));
hideBottomSheet();
Assert.assertNull(mItemClicked);
Assert.assertTrue(mCallbackInvoked);
......
......@@ -3096,6 +3096,9 @@ Data from your Incognito session will only be cleared from Chrome when you <ph n
<message name="IDS_READING_LIST_TITLE" desc="The title for the reading list page in main bookmark UI.">
Reading list
</message>
<message name="IDS_READING_LIST_TITLE_NEW" desc="The title for the reading list with a new text.">
Reading list <ph name="BEGIN_NEW">&lt;new&gt;</ph>New<ph name="END_NEW">&lt;/new&gt;</ph>
</message>
<message name="IDS_READING_LIST_READ" desc="The header for the read section in the reading list UI.">
Read
</message>
......
50889cf3fbf93573b8531e5d2ef95907c0b57f11
\ No newline at end of file
......@@ -67,6 +67,7 @@ public @interface FeatureConstants {
String READ_LATER_CONTEXT_MENU_FEATURE = "IPH_ReadLaterContextMenu";
String READ_LATER_APP_MENU_BOOKMARK_THIS_PAGE_FEATURE = "IPH_ReadLaterAppMenuBookmarkThisPage";
String READ_LATER_APP_MENU_BOOKMARKS_FEATURE = "IPH_ReadLaterAppMenuBookmarks";
String READ_LATER_BOTTOM_SHEET_FEATURE = "IPH_ReadLaterBottomSheet";
/**
* An IPH feature that encourages users to get better translations by enabling access to page
......
......@@ -81,6 +81,8 @@ const base::Feature kIPHReadLaterAppMenuBookmarkThisPageFeature{
"IPH_ReadLaterAppMenuBookmarkThisPage", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHReadLaterAppMenuBookmarksFeature{
"IPH_ReadLaterAppMenuBookmarks", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHReadLaterBottomSheetFeature{
"IPH_ReadLaterBottomSheet", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHEphemeralTabFeature{"IPH_EphemeralTab",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHFeedCardMenuFeature{"IPH_FeedCardMenu",
......
......@@ -68,6 +68,7 @@ extern const base::Feature kIPHQuietNotificationPromptsFeature;
extern const base::Feature kIPHReadLaterContextMenuFeature;
extern const base::Feature kIPHReadLaterAppMenuBookmarkThisPageFeature;
extern const base::Feature kIPHReadLaterAppMenuBookmarksFeature;
extern const base::Feature kIPHReadLaterBottomSheetFeature;
extern const base::Feature kIPHTabGroupsQuicklyComparePagesFeature;
extern const base::Feature kIPHTabGroupsTapToSeeAnotherTabFeature;
extern const base::Feature kIPHTabGroupsYourTabsAreTogetherFeature;
......
......@@ -52,6 +52,7 @@ const base::Feature* const kAllFeatures[] = {
&kIPHReadLaterContextMenuFeature,
&kIPHReadLaterAppMenuBookmarkThisPageFeature,
&kIPHReadLaterAppMenuBookmarksFeature,
&kIPHReadLaterBottomSheetFeature,
&kIPHTabGroupsQuicklyComparePagesFeature,
&kIPHTabGroupsTapToSeeAnotherTabFeature,
&kIPHTabGroupsYourTabsAreTogetherFeature,
......
......@@ -105,6 +105,8 @@ DEFINE_VARIATION_PARAM(kIPHReadLaterAppMenuBookmarkThisPageFeature,
"IPH_ReadLaterAppMenuBookmarkThisPage");
DEFINE_VARIATION_PARAM(kIPHReadLaterAppMenuBookmarksFeature,
"IPH_ReadLaterAppMenuBookmarks");
DEFINE_VARIATION_PARAM(kIPHReadLaterBottomSheetFeature,
"IPH_ReadLaterBottomSheet");
DEFINE_VARIATION_PARAM(kIPHTabGroupsQuicklyComparePagesFeature,
"IPH_TabGroupsQuicklyComparePages");
DEFINE_VARIATION_PARAM(kIPHTabGroupsTapToSeeAnotherTabFeature,
......@@ -201,6 +203,7 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHReadLaterContextMenuFeature),
VARIATION_ENTRY(kIPHReadLaterAppMenuBookmarkThisPageFeature),
VARIATION_ENTRY(kIPHReadLaterAppMenuBookmarksFeature),
VARIATION_ENTRY(kIPHReadLaterBottomSheetFeature),
VARIATION_ENTRY(kIPHTabGroupsQuicklyComparePagesFeature),
VARIATION_ENTRY(kIPHTabGroupsTapToSeeAnotherTabFeature),
VARIATION_ENTRY(kIPHTabGroupsYourTabsAreTogetherFeature),
......
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