0

[Start] Add IPH for the home button on tab switcher page.

Bug: 1219498
Change-Id: I86e63394c68aa8e0087c1f2813aef68fc2d8f85b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2939462
Reviewed-by: Yashar Dabiran <yashard@chromium.org>
Reviewed-by: David Trainor <dtrainor@chromium.org>
Reviewed-by: Yaron Friedman <yfriedman@chromium.org>
Reviewed-by: Xi Han <hanxi@chromium.org>
Commit-Queue: Hao Dong <spdonghao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#894029}
This commit is contained in:
spdonghao
2021-06-18 23:57:57 +00:00
committed by Chromium LUCI CQ
parent 86edae5b23
commit 9123e9c6cc
17 changed files with 236 additions and 26 deletions

@ -1194,6 +1194,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonProperties.java",
"java/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonViewBinder.java",
"java/src/org/chromium/chrome/browser/toolbar/top/OptionalBrowsingModeButtonController.java",
"java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceHomeButtonIPHController.java",
"java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java",
"java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java",
"java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarProperties.java",

@ -1,16 +1,19 @@
noparent = True
include_rules = [
# Allow dependencies on chrome/browser modules
"+chrome/browser",
# Restrict dependencies to xsurface by default (crbug.com/1115137)
"-chrome/browser/xsurface",
"-chrome/android/java/src/org/chromium/chrome/browser",
"+base/android/java/src/org/chromium/base",
"+chrome/android/java/src/org/chromium/chrome/browser/toolbar",
"+chrome/android/java/src/org/chromium/chrome/browser/omnibox",
"+chrome/browser/ui/android/theme",
"+components/browser_ui/widget/android/java",
"+ui/android/java/src/org/chromium/ui",
"+url/android",
"+chrome/browser/tabmodel/android/java",
"+chrome/browser/ui/messages/android/java",
"+components/browser_ui/bottomsheet/android/java",
]
@ -22,7 +25,6 @@ specific_include_rules = {
"+chrome/android/java/src/org/chromium/chrome/browser",
"-chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
"-chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java",
"+chrome/browser/ui/android/toolbar",
],
'ToolbarButtonInProductHelpController.java': [
"+chrome/android/java/src/org/chromium/chrome/browser",
@ -32,7 +34,4 @@ specific_include_rules = {
'LocationBarModel.java': [
"+chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java",
],
'ToolbarControlContainer.java': [
"+chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags",
]
}

@ -1,6 +1,4 @@
include_rules = [
"+chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel",
"+chrome/browser/ui/android/layouts",
"+chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar",
"+chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java",
"+chrome/android/java/src/org/chromium/chrome/browser/incognito",
"+components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement",
]

@ -0,0 +1,78 @@
// Copyright 2021 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.toolbar.top;
import android.view.View;
import androidx.annotation.VisibleForTesting;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.user_education.IPHCommand;
import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
import org.chromium.chrome.browser.user_education.UserEducationHelper;
import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightParams;
import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightShape;
import org.chromium.components.feature_engagement.EventConstants;
import org.chromium.components.feature_engagement.FeatureConstants;
import org.chromium.components.feature_engagement.Tracker;
/**
* Controller to manage when and how we show home button in-product-help messages on the tab
* switcher when start surface is enabled to users.
*/
public class StartSurfaceHomeButtonIPHController {
private final UserEducationHelper mUserEducationHelper;
private final IPHCommand mIPHCommand;
private boolean mIsShowingIPH;
public StartSurfaceHomeButtonIPHController(
UserEducationHelper userEducationHelper, View homeButtonView) {
mUserEducationHelper = userEducationHelper;
mIPHCommand = new IPHCommandBuilder(homeButtonView.getResources(),
FeatureConstants.START_SURFACE_TAB_SWITCHER_HOME_BUTTON_FEATURE,
org.chromium.chrome.R.string.iph_ntp_with_feed_text,
org.chromium.chrome.R.string.iph_ntp_with_feed_accessibility_text)
.setAnchorView(homeButtonView)
.setHighlightParams(new HighlightParams(HighlightShape.CIRCLE))
.setDismissOnTouch(true)
.setOnShowCallback(() -> mIsShowingIPH = true)
.setOnDismissCallback(() -> mIsShowingIPH = false)
.setAutoDismissTimeout(10 * 1000)
.build();
}
public void maybeShowIPH() {
if (!mIsShowingIPH) {
mUserEducationHelper.requestShowIPH(mIPHCommand);
}
}
/**
* Record the home button has been clicked when IPH is showing.
*/
public void onHomeButtonClicked() {
if (mIsShowingIPH) {
Tracker tracker =
TrackerFactory.getTrackerForProfile(Profile.getLastUsedRegularProfile());
tracker.notifyEvent(EventConstants.START_SURFACE_TAB_SWITCHER_HOME_BUTTON_CLICKED);
}
}
@VisibleForTesting
boolean isShowingHomeButtonIPHForTesting() {
return mIsShowingIPH;
}
@VisibleForTesting
void setIsShowingIPHForTesting(boolean isShowing) {
mIsShowingIPH = isShowing;
}
@VisibleForTesting
IPHCommand getIPHCommand() {
return mIPHCommand;
}
}

@ -95,7 +95,7 @@ public class StartSurfaceToolbarCoordinator {
homepageEnabledSupplier, startSurfaceAsHomepageSupplier,
homepageManagedByPolicySupplier, homeButtonOnClickHandler,
StartSurfaceConfiguration.shouldShowNewSurfaceFromHomeButton(),
isTabGroupsAndroidContinuationEnabled);
isTabGroupsAndroidContinuationEnabled, userEducationHelper);
mThemeColorProvider = provider;
mMenuButtonCoordinator = menuButtonCoordinator;
@ -259,6 +259,8 @@ public class StartSurfaceToolbarCoordinator {
mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(
mPropertyModel, mView, StartSurfaceToolbarViewBinder::bind);
mToolbarMediator.setHomeButtonView(mView.getHomeButtonView());
if (StartSurfaceConfiguration.shouldShowNewSurfaceFromHomeButton()) {
mTabSwitcherButtonView = mView.findViewById(R.id.start_tab_switcher_button);
if (mTabSwitcherLongClickListener != null) {

@ -52,6 +52,7 @@ import org.chromium.chrome.browser.toolbar.ButtonData.ButtonSpec;
import org.chromium.chrome.browser.toolbar.TabCountProvider;
import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator;
import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
import org.chromium.chrome.browser.user_education.UserEducationHelper;
import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
import org.chromium.chrome.features.start_surface.StartSurfaceState;
import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
@ -60,11 +61,12 @@ import org.chromium.ui.modelutil.PropertyModel;
/** The mediator implements interacts between the views and the caller. */
class StartSurfaceToolbarMediator {
private final PropertyModel mPropertyModel;
private final Callback<IPHCommandBuilder> mShowIPHCallback;
private final Callback<IPHCommandBuilder> mShowIdentityIPHCallback;
private final boolean mHideIncognitoSwitchWhenNoTabs;
private final boolean mShouldShowTabSwitcherButtonOnHomepage;
private final Supplier<ButtonData> mIdentityDiscButtonSupplier;
private final boolean mIsTabGroupsAndroidContinuationEnabled;
private final UserEducationHelper mUserEducationHelper;
private TabModelSelector mTabModelSelector;
private TabCountProvider mTabCountProvider;
@ -83,8 +85,11 @@ class StartSurfaceToolbarMediator {
private float mNonIncognitoHomepageTranslationY;
private boolean mShowHomeButtonOnTabSwitcher;
private StartSurfaceHomeButtonIPHController mStartSurfaceHomeButtonIPHController;
private View mHomeButtonView;
StartSurfaceToolbarMediator(PropertyModel model, Callback<IPHCommandBuilder> showIPHCallback,
StartSurfaceToolbarMediator(PropertyModel model,
Callback<IPHCommandBuilder> showIdentityIPHCallback,
boolean hideIncognitoSwitchWhenNoTabs, boolean showHomeButtonOnTabSwitcher,
MenuButtonCoordinator menuButtonCoordinator,
ObservableSupplier<Boolean> identityDiscStateSupplier,
@ -93,14 +98,16 @@ class StartSurfaceToolbarMediator {
ObservableSupplier<Boolean> startSurfaceAsHomepageSupplier,
ObservableSupplier<Boolean> homepageManagedByPolicySupplier,
OnClickListener homeButtonOnClickHandler, boolean shouldShowTabSwitcherButtonOnHomepage,
boolean isTabGroupsAndroidContinuationEnabled) {
boolean isTabGroupsAndroidContinuationEnabled,
UserEducationHelper userEducationHelper) {
mPropertyModel = model;
mOverviewModeState = StartSurfaceState.NOT_SHOWN;
mShowIPHCallback = showIPHCallback;
mShowIdentityIPHCallback = showIdentityIPHCallback;
mHideIncognitoSwitchWhenNoTabs = hideIncognitoSwitchWhenNoTabs;
mMenuButtonCoordinator = menuButtonCoordinator;
mIdentityDiscButtonSupplier = identityDiscButtonSupplier;
mIsTabGroupsAndroidContinuationEnabled = isTabGroupsAndroidContinuationEnabled;
mUserEducationHelper = userEducationHelper;
identityDiscStateSupplier.addObserver((canShowHint) -> {
// If the identity disc wants to be hidden and is hidden, there's nothing we need to do.
if (!canShowHint && !mPropertyModel.get(IDENTITY_DISC_IS_VISIBLE)) return;
@ -116,7 +123,16 @@ class StartSurfaceToolbarMediator {
}));
mPropertyModel.set(
HOMEPAGE_MANAGED_BY_POLICY_SUPPLIER, homepageManagedByPolicySupplier);
mPropertyModel.set(HOME_BUTTON_CLICK_HANDLER, homeButtonOnClickHandler);
View.OnClickListener homeButtonOnClickListener = v -> {
if (homeButtonOnClickHandler != null) homeButtonOnClickHandler.onClick(v);
if (mStartSurfaceHomeButtonIPHController != null) {
mStartSurfaceHomeButtonIPHController.onHomeButtonClicked();
}
};
mPropertyModel.set(HOME_BUTTON_CLICK_HANDLER, homeButtonOnClickListener);
startSurfaceAsHomepageSupplier.addObserver(
mCallbackController.makeCancelable((showStartSurfaceAsHomepage) -> {
mShouldShowStartSurfaceAsHomepage = showStartSurfaceAsHomepage;
@ -356,6 +372,10 @@ class StartSurfaceToolbarMediator {
mPropertyModel.set(NEW_TAB_BUTTON_HIGHLIGHT, highlight);
}
void setHomeButtonView(View homeButtonView) {
mHomeButtonView = homeButtonView;
}
private void updateLogoVisibility(boolean isGoogleSearchEngine) {
mIsGoogleSearchEngine = isGoogleSearchEngine;
boolean shouldShowLogo =
@ -375,7 +395,7 @@ class StartSurfaceToolbarMediator {
IDENTITY_DISC_IMAGE, buttonSpec.getDrawable().getConstantState().newDrawable());
mPropertyModel.set(IDENTITY_DISC_DESCRIPTION, buttonSpec.getContentDescriptionResId());
mPropertyModel.set(IDENTITY_DISC_IS_VISIBLE, true);
mShowIPHCallback.onResult(buttonSpec.getIPHCommandBuilder());
mShowIdentityIPHCallback.onResult(buttonSpec.getIPHCommandBuilder());
} else {
mPropertyModel.set(IDENTITY_DISC_IS_VISIBLE, false);
}
@ -394,11 +414,21 @@ class StartSurfaceToolbarMediator {
private void updateHomeButtonVisibility() {
boolean isShownTabSwitcherState = mOverviewModeState == StartSurfaceState.SHOWN_TABSWITCHER;
boolean shouldShow = mHomepageEnabled && isShownTabSwitcherState
&& !mPropertyModel.get(IS_INCOGNITO) && mShowHomeButtonOnTabSwitcher
&& mShouldShowStartSurfaceAsHomepage;
// If start surface is not shown as the homepage, home button shouldn't be shown on tab
// switcher page.
mPropertyModel.set(HOME_BUTTON_IS_VISIBLE,
mHomepageEnabled && isShownTabSwitcherState && !mPropertyModel.get(IS_INCOGNITO)
&& mShowHomeButtonOnTabSwitcher && mShouldShowStartSurfaceAsHomepage);
mPropertyModel.set(HOME_BUTTON_IS_VISIBLE, shouldShow);
// If the home button is shown, maybe show the IPH.
if (shouldShow) {
if (mStartSurfaceHomeButtonIPHController == null) {
mStartSurfaceHomeButtonIPHController = new StartSurfaceHomeButtonIPHController(
mUserEducationHelper, mHomeButtonView);
}
mStartSurfaceHomeButtonIPHController.maybeShowIPH();
}
}
private void updateTabSwitcherButtonVisibility() {
@ -433,4 +463,10 @@ class StartSurfaceToolbarMediator {
void setShowHomeButtonOnTabSwitcherForTesting(boolean showHomeButtonOnTabSwitcher) {
mShowHomeButtonOnTabSwitcher = showHomeButtonOnTabSwitcher;
}
@VisibleForTesting
void setStartSurfaceHomeButtonIPHControllerForTesting(
StartSurfaceHomeButtonIPHController startSurfaceHomeButtonIPHController) {
mStartSurfaceHomeButtonIPHController = startSurfaceHomeButtonIPHController;
}
}

@ -246,6 +246,11 @@ class StartSurfaceToolbarView extends RelativeLayout {
return mIdentityDiscButton;
}
/** Return the home button view. */
View getHomeButtonView() {
return mHomeButton;
}
/**
* @param isAtStart Whether the identity disc is at start.
*/

@ -13,8 +13,10 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.BUTTONS_CLICKABLE;
import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.HOME_BUTTON_CLICK_HANDLER;
import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.HOME_BUTTON_IS_VISIBLE;
import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_AT_START;
import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_CLICK_HANDLER;
@ -47,9 +49,11 @@ import org.robolectric.annotation.Config;
import org.chromium.base.Callback;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.identity_disc.IdentityDiscController;
import org.chromium.chrome.browser.layouts.LayoutStateProvider;
import org.chromium.chrome.browser.layouts.LayoutType;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModel;
@ -59,8 +63,11 @@ import org.chromium.chrome.browser.toolbar.ButtonData.ButtonSpec;
import org.chromium.chrome.browser.toolbar.ButtonDataImpl;
import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator;
import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
import org.chromium.chrome.browser.user_education.UserEducationHelper;
import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
import org.chromium.chrome.features.start_surface.StartSurfaceState;
import org.chromium.components.feature_engagement.EventConstants;
import org.chromium.components.feature_engagement.Tracker;
import org.chromium.components.search_engines.TemplateUrlService;
import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
import org.chromium.ui.modelutil.PropertyModel;
@ -92,11 +99,21 @@ public class StartSurfaceToolbarMediatorUnitTest {
@Mock
Drawable.ConstantState mMockConstantState;
@Mock
Callback<IPHCommandBuilder> mMockCallback;
Callback<IPHCommandBuilder> mMockIdentityIPHCallback;
@Mock
Tab mMockIncognitoTab;
@Mock
MenuButtonCoordinator mMenuButtonCoordinator;
@Mock
UserEducationHelper mUserEducationHelper;
@Mock
View mHomeButtonView;
@Mock
Resources mResources;
@Mock
private Profile mProfile;
@Mock
Tracker mTracker;
@Captor
private ArgumentCaptor<LayoutStateProvider.LayoutStateObserver> mLayoutStateObserverCaptor;
@Captor
@ -109,6 +126,7 @@ public class StartSurfaceToolbarMediatorUnitTest {
private ObservableSupplierImpl<Boolean> mIdentityDiscStateSupplier;
private ObservableSupplierImpl<Boolean> mStartSurfaceAsHomepageSupplier;
private ObservableSupplierImpl<Boolean> mHomepageEnabledSupplier;
private StartSurfaceHomeButtonIPHController mStartSurfaceHomeButtonIPHController;
@Before
public void setUp() {
@ -129,6 +147,12 @@ public class StartSurfaceToolbarMediatorUnitTest {
mHomepageEnabledSupplier = new ObservableSupplierImpl<>();
mHomepageEnabledSupplier.set(true);
Profile.setLastUsedProfileForTesting(mProfile);
when(mHomeButtonView.getResources()).thenReturn(mResources);
TrackerFactory.setTrackerForTests(mTracker);
mStartSurfaceHomeButtonIPHController =
new StartSurfaceHomeButtonIPHController(mUserEducationHelper, mHomeButtonView);
doReturn(mButtonData)
.when(mIdentityDiscController)
.getForStartSurface(StartSurfaceState.SHOWN_HOMEPAGE);
@ -424,7 +448,7 @@ public class StartSurfaceToolbarMediatorUnitTest {
mMediator.updateIdentityDisc(mButtonData);
assertTrue(mPropertyModel.get(IDENTITY_DISC_IS_VISIBLE));
verify(mMockCallback, times(1))
verify(mMockIdentityIPHCallback, times(1))
.onResult(mButtonData.getButtonSpec().getIPHCommandBuilder());
}
@ -680,6 +704,27 @@ public class StartSurfaceToolbarMediatorUnitTest {
assertFalse(mPropertyModel.get(HOME_BUTTON_IS_VISIBLE));
}
@Test
public void testShowHomeButtonIPH() {
createMediator(false, true, false, false);
// Show tab switcher surface and the IPH should show.
assertFalse(mStartSurfaceHomeButtonIPHController.isShowingHomeButtonIPHForTesting());
mMediator.setStartSurfaceMode(true);
mLayoutStateObserverCaptor.getValue().onStartedShowing(LayoutType.TAB_SWITCHER, false);
mLayoutStateObserverCaptor.getValue().onFinishedShowing(LayoutType.TAB_SWITCHER);
mMediator.onStartSurfaceStateChanged(StartSurfaceState.SHOWN_TABSWITCHER, true);
assertTrue(mPropertyModel.get(HOME_BUTTON_IS_VISIBLE));
verify(mUserEducationHelper, times(1))
.requestShowIPH(mStartSurfaceHomeButtonIPHController.getIPHCommand());
// When the IPH is showing and the home button is clicked,
// START_SURFACE_TAB_SWITCHER_HOME_BUTTON_CLICKED event should be notified.
mStartSurfaceHomeButtonIPHController.setIsShowingIPHForTesting(true);
mPropertyModel.get(HOME_BUTTON_CLICK_HANDLER).onClick(mHomeButtonView);
verify(mTracker).notifyEvent(EventConstants.START_SURFACE_TAB_SWITCHER_HOME_BUTTON_CLICKED);
}
@Test
public void testNewHomeSurface() {
createMediator(false, true, true, false);
@ -752,7 +797,7 @@ public class StartSurfaceToolbarMediatorUnitTest {
private void createMediator(boolean hideIncognitoSwitchWhenNoTabs,
boolean showHomeButtonOnTabSwitcher, boolean shouldShowTabSwitcherButtonOnHomepage,
boolean isTabGroupsAndroidContinuationEnabled) {
mMediator = new StartSurfaceToolbarMediator(mPropertyModel, mMockCallback,
mMediator = new StartSurfaceToolbarMediator(mPropertyModel, mMockIdentityIPHCallback,
hideIncognitoSwitchWhenNoTabs, showHomeButtonOnTabSwitcher, mMenuButtonCoordinator,
mIdentityDiscStateSupplier,
()
@ -760,9 +805,11 @@ public class StartSurfaceToolbarMediatorUnitTest {
mMediator.getOverviewModeStateForTesting()),
mHomepageEnabledSupplier, mStartSurfaceAsHomepageSupplier,
new ObservableSupplierImpl<>(), null, shouldShowTabSwitcherButtonOnHomepage,
isTabGroupsAndroidContinuationEnabled);
isTabGroupsAndroidContinuationEnabled, mUserEducationHelper);
mMediator.setLayoutStateProvider(mLayoutStateProvider);
mMediator.setStartSurfaceHomeButtonIPHControllerForTesting(
mStartSurfaceHomeButtonIPHController);
verify(mLayoutStateProvider).addObserver(mLayoutStateObserverCaptor.capture());
}
}

@ -253,6 +253,10 @@ public final class EventConstants {
/** WebFeed events. */
public static final String WEB_FEED_FOLLOW_INTRO_CLICKED = "web_feed_follow_intro_clicked";
/** Tab switcher home button events. */
public static final String START_SURFACE_TAB_SWITCHER_HOME_BUTTON_CLICKED =
"start_surface_tab_switcher_home_button_clicked";
/**
* Do not instantiate.
*/

@ -55,7 +55,8 @@ import java.lang.annotation.RetentionPolicy;
FeatureConstants.PWA_INSTALL_AVAILABLE_FEATURE, FeatureConstants.PAGE_INFO_FEATURE,
FeatureConstants.IPH_SHARE_SCREENSHOT_FEATURE, FeatureConstants.IPH_WEB_FEED_FOLLOW_FEATURE,
FeatureConstants.IPH_WEB_FEED_POST_FOLLOW_DIALOG_FEATURE,
FeatureConstants.SHARED_HIGHLIGHTING_BUILDER_FEATURE})
FeatureConstants.SHARED_HIGHLIGHTING_BUILDER_FEATURE,
FeatureConstants.START_SURFACE_TAB_SWITCHER_HOME_BUTTON_FEATURE})
@Retention(RetentionPolicy.SOURCE)
public @interface FeatureConstants {
String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_NEW_TAB_FEATURE =
@ -273,4 +274,10 @@ public @interface FeatureConstants {
* An IPH feature to inform users about the link-to-text on selection share.
*/
String SHARED_HIGHLIGHTING_BUILDER_FEATURE = "IPH_SharedHighlightingBuilder";
/**
* An IPH feature to prompt users to click home button on the tab switcher surface when start
* surface is enabled.
*/
String START_SURFACE_TAB_SWITCHER_HOME_BUTTON_FEATURE = "IPH_StartSurfaceTabSwitcherHomeButton";
}

@ -227,6 +227,28 @@ absl::optional<FeatureConfig> GetClientSideFeatureConfig(
Comparator(ANY, 0), 360, 360);
return config;
}
if (kIPHStartSurfaceTabSwitcherHomeButton.name == feature->name) {
// A config that allows the StartSurfaceTabSwitcherHomeButton IPH to be
// shown:
// * Once per day
// * Up to 7 times but only if the home button is not clicked when IPH is
// showing.
absl::optional<FeatureConfig> config = FeatureConfig();
config->valid = true;
config->availability = Comparator(ANY, 0);
config->session_rate = Comparator(ANY, 0);
config->trigger =
EventConfig("start_surface_tab_switcher_home_button_iph_trigger",
Comparator(LESS_THAN, 7), k10YearsInDays, k10YearsInDays);
config->used =
EventConfig("start_surface_tab_switcher_home_button_clicked",
Comparator(EQUAL, 0), k10YearsInDays, k10YearsInDays);
config->event_configs.insert(
EventConfig("start_surface_tab_switcher_home_button_iph_trigger",
Comparator(EQUAL, 0), 1, 360));
return config;
}
#endif // defined(OS_ANDROID)
if (kIPHDummyFeature.name == feature->name) {

@ -180,6 +180,8 @@ const base::Feature kIPHWebFeedPostFollowDialogFeature{
"IPH_WebFeedPostFollowDialog", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHSharedHighlightingBuilder{
"IPH_SharedHighlightingBuilder", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHStartSurfaceTabSwitcherHomeButton{
"IPH_StartSurfaceTabSwitcherHomeButton", base::FEATURE_ENABLED_BY_DEFAULT};
#endif // defined(OS_ANDROID)
#if defined(OS_IOS)

@ -107,6 +107,7 @@ extern const base::Feature kIPHShareScreenshotFeature;
extern const base::Feature kIPHWebFeedFollowFeature;
extern const base::Feature kIPHWebFeedPostFollowDialogFeature;
extern const base::Feature kIPHSharedHighlightingBuilder;
extern const base::Feature kIPHStartSurfaceTabSwitcherHomeButton;
#endif // defined(OS_ANDROID)
#if defined(OS_IOS)

@ -80,6 +80,7 @@ const base::Feature* const kAllFeatures[] = {
&kIPHWebFeedFollowFeature,
&kIPHWebFeedPostFollowDialogFeature,
&kIPHSharedHighlightingBuilder,
&kIPHStartSurfaceTabSwitcherHomeButton,
#endif // defined(OS_ANDROID)
#if defined(OS_IOS)
&kIPHBottomToolbarTipFeature,

@ -155,6 +155,8 @@ DEFINE_VARIATION_PARAM(kIPHWebFeedPostFollowDialogFeature,
"IPH_WebFeedPostFollowDialog");
DEFINE_VARIATION_PARAM(kIPHSharedHighlightingBuilder,
"IPH_SharedHighlightingBuilder");
DEFINE_VARIATION_PARAM(kIPHStartSurfaceTabSwitcherHomeButton,
"IPH_StartSurfaceTabSwitcherHomeButton");
#endif // defined(OS_ANDROID)
#if defined(OS_IOS)
DEFINE_VARIATION_PARAM(kIPHBottomToolbarTipFeature, "IPH_BottomToolbarTip");

@ -28590,6 +28590,8 @@ should be able to be added at any place in this file.
<suffix name="ReopenTab" label="For ReopenTab feature."/>
<suffix name="SharedHighlightingBuilder"
label="For SharedHighlightingBuilder feature."/>
<suffix name="StartSurfaceTabSwitcherHomeButton"
label="For StartSurfaceTabSwitcherHomeButton feature."/>
<suffix name="TabGroupsDragAndDrop" label="For drop-to-merge in tab group."/>
<suffix name="TabGroupsQuicklyComparePages"
label="For long press links to create tab groups."/>

@ -8299,6 +8299,9 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
<suffix name="IPH_SharedHighlightingBuilder"
label="The in product help message to notify the user that the share
action can preemptively share a link-to-text."/>
<suffix name="IPH_StartSurfaceTabSwitcherHomeButton"
label="In product help for home button on the tab switcher when start
surface is enabled."/>
<suffix name="IPH_TabGroupsDragAndDrop"
label="In product help for educating user to drop one tab on another
tab to create group."/>