Commit 6a609dd2 authored by Gauthier Ambard's avatar Gauthier Ambard Committed by Commit Bot

Add Bottom Toolbar tip

This CL adds in product help for the bottom toolbar.
The tip is triggered when the user opens the app on iPhone portrait.

Bug: 830635
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: Id5de92a2eafa4f7e2453c80f865ab4c612c42160
Reviewed-on: https://chromium-review.googlesource.com/1076131Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Commit-Queue: Gauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#562756}
parent 6b5097e5
......@@ -63,6 +63,8 @@ const base::Feature kIPHNewTabFeature{"IPH_NewTab",
#endif // BUILDFLAG(ENABLE_DESKTOP_IPH)
#if defined(OS_IOS)
const base::Feature kIPHBottomToolbarTipFeature{
"IPH_BottomToolbarTip", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHNewTabTipFeature{"IPH_NewTabTip",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHNewIncognitoTabTipFeature{
......
......@@ -48,6 +48,7 @@ extern const base::Feature kIPHNewTabFeature;
#endif // BUILDFLAG(ENABLE_DESKTOP_IPH)
#if defined(OS_IOS)
extern const base::Feature kIPHBottomToolbarTipFeature;
extern const base::Feature kIPHNewTabTipFeature;
extern const base::Feature kIPHNewIncognitoTabTipFeature;
extern const base::Feature kIPHBadgedReadingListFeature;
......
......@@ -41,6 +41,7 @@ const base::Feature* const kAllFeatures[] = {
&kIPHNewTabFeature,
#endif // BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
#if defined(OS_IOS)
&kIPHBottomToolbarTipFeature,
&kIPHNewTabTipFeature,
&kIPHNewIncognitoTabTipFeature,
&kIPHBadgedReadingListFeature,
......
......@@ -80,6 +80,7 @@ DEFINE_VARIATION_PARAM(kIPHIncognitoWindowFeature, "IPH_IncognitoWindow");
DEFINE_VARIATION_PARAM(kIPHNewTabFeature, "IPH_NewTab");
#endif // BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
#if defined(OS_IOS)
DEFINE_VARIATION_PARAM(kIPHBottomToolbarTipFeature, "IPH_BottomToolbarTip");
DEFINE_VARIATION_PARAM(kIPHNewTabTipFeature, "IPH_NewTabTip");
DEFINE_VARIATION_PARAM(kIPHNewIncognitoTabTipFeature, "IPH_NewIncognitoTabTip");
DEFINE_VARIATION_PARAM(kIPHBadgedReadingListFeature, "IPH_BadgedReadingList");
......@@ -116,6 +117,7 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHIncognitoWindowFeature),
VARIATION_ENTRY(kIPHNewTabFeature),
#elif defined(OS_IOS)
VARIATION_ENTRY(kIPHBottomToolbarTipFeature),
VARIATION_ENTRY(kIPHNewTabTipFeature),
VARIATION_ENTRY(kIPHNewIncognitoTabTipFeature),
VARIATION_ENTRY(kIPHBadgedReadingListFeature),
......
......@@ -447,6 +447,9 @@ locale. The strings in this file are specific to iOS.
<message name="IDS_IOS_BOOKMARK_URL_FIELD_VALIDATION_FAILED" desc="Error message shown below URL input field when the URL is incorrect. [Length: 20em]">
Invalid URL
</message>
<message name="IDS_IOS_BOTTOM_TOOLBAR_IPH_PROMOTION_TEXT" desc="Text for the Bottom Toolbar Tip in-product help promotion, explaining that the bottom toolbar can be used to focus the Search Bar, instead of having to reach to the top toolbar. [iOS only]">
Search bar is now easier to reach
</message>
<message name="IDS_IOS_CAMERA_USAGE_DESCRIPTION" desc="Specifies the reason for accessing the user's camera while the app is in use [Length: unlimited] [iOS only].">
This lets you take and upload photos.
</message>
......
......@@ -684,6 +684,11 @@ NSString* const kBrowserViewControllerSnackbarCategory =
// Coordinator for the popup menus.
@property(nonatomic, strong) PopupMenuCoordinator* popupMenuCoordinator;
// Used to display the bottom toolbar tip in-product help promotion bubble.
// |nil| if the tip bubble has not yet been presented. Once the bubble is
// dismissed, it remains allocated so that |userEngaged| remains accessible.
@property(nonatomic, strong)
BubbleViewControllerPresenter* bottomToolbarTipBubblePresenter;
// Used to display the new tab tip in-product help promotion bubble. |nil| if
// the new tab tip bubble has not yet been presented. Once the bubble is
// dismissed, it remains allocated so that |userEngaged| remains accessible.
......@@ -958,6 +963,7 @@ bubblePresenterForFeature:(const base::Feature&)feature
@synthesize tabStripCoordinator = _tabStripCoordinator;
@synthesize tabStripView = _tabStripView;
@synthesize popupMenuCoordinator = _popupMenuCoordinator;
@synthesize bottomToolbarTipBubblePresenter = _bottomToolbarTipBubblePresenter;
@synthesize tabTipBubblePresenter = _tabTipBubblePresenter;
@synthesize incognitoTabTipBubblePresenter = _incognitoTabTipBubblePresenter;
@synthesize primaryToolbarCoordinator = _primaryToolbarCoordinator;
......@@ -1416,6 +1422,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
- (void)presentBubblesIfEligible {
[self presentNewTabTipBubbleOnInitialized];
[self presentNewIncognitoTabTipBubbleOnInitialized];
[self presentBottomToolbarTipBubbleOnInitialized];
}
- (void)browserStateDestroyed {
......@@ -2705,6 +2712,80 @@ bubblePresenterForFeature:(const base::Feature&)feature
return bubbleViewControllerPresenter;
}
// Waits to present a bubble associated with the bottom toolbar tip in-product
// help promotion until the feature engagement tracker database is fully
// initialized. This method requires that |self.browserState| is not NULL.
- (void)presentBottomToolbarTipBubbleOnInitialized {
DCHECK(self.browserState);
// If the tip bubble has already been presented and the user is still
// considered engaged, it can't be overwritten or set to |nil| or else it will
// reset the |userEngaged| property. Once the user is not engaged, the bubble
// can be safely overwritten or set to |nil|.
if (!self.bottomToolbarTipBubblePresenter.isUserEngaged) {
__weak BrowserViewController* weakSelf = self;
void (^onInitializedBlock)(bool) = ^(bool successfullyLoaded) {
if (!successfullyLoaded)
return;
[weakSelf presentBottomToolbarTipBubble];
};
// Because the new tab tip occurs on startup, the feature engagement
// tracker's database is not guaranteed to be loaded by this time. For the
// bubble to appear properly, a callback is used to guarantee the event data
// is loaded before the check to see if the promotion should be displayed.
feature_engagement::TrackerFactory::GetForBrowserState(self.browserState)
->AddOnInitializedCallback(base::BindBlockArc(onInitializedBlock));
}
}
// Presents a bubble associated with the bottom toolbar tip in-product help
// promotion. This method requires that |self.browserState| is not NULL.
- (void)presentBottomToolbarTipBubble {
if (!IsSplitToolbarMode())
return;
DCHECK(self.browserState);
// If the BVC is not visible, do not present the bubble.
if (!self.viewVisible)
return;
// Do not present the bubble if there is no current tab.
Tab* currentTab = [self.tabModel currentTab];
if (!currentTab)
return;
// Do not present the bubble if the tab is not scrolled to the top.
if (![self isTabScrolledToTop:currentTab])
return;
BubbleArrowDirection arrowDirection = BubbleArrowDirectionDown;
NSString* text = l10n_util::GetNSStringWithFixup(
IDS_IOS_BOTTOM_TOOLBAR_IPH_PROMOTION_TEXT);
UILayoutGuide* guide =
[NamedGuide guideWithName:kSearchButtonGuide view:self.view];
DCHECK(guide);
CGPoint anchorPoint =
bubble_util::AnchorPoint(guide.layoutFrame, arrowDirection);
CGPoint tipAnchor = [guide.owningView convertPoint:anchorPoint
toView:guide.owningView.window];
// If the feature engagement tracker does not consider it valid to display
// the new tab tip, then end early to prevent the potential reassignment
// of the existing |bottomToolbarTipBubblePresenter| to nil.
BubbleViewControllerPresenter* presenter = [self
bubblePresenterForFeature:feature_engagement::kIPHBottomToolbarTipFeature
direction:arrowDirection
alignment:BubbleAlignmentCenter
text:text];
if (!presenter)
return;
self.bottomToolbarTipBubblePresenter = presenter;
[self.bottomToolbarTipBubblePresenter presentInViewController:self
view:self.view
anchorPoint:tipAnchor];
}
- (void)presentNewTabTipBubbleOnInitialized {
DCHECK(self.browserState);
// If the tab tip bubble has already been presented and the user is still
......@@ -2714,6 +2795,8 @@ bubblePresenterForFeature:(const base::Feature&)feature
if (!self.tabTipBubblePresenter.isUserEngaged) {
__weak BrowserViewController* weakSelf = self;
void (^onInitializedBlock)(bool) = ^(bool successfullyLoaded) {
if (!successfullyLoaded)
return;
[weakSelf presentNewTabTipBubble];
};
......@@ -2788,6 +2871,8 @@ bubblePresenterForFeature:(const base::Feature&)feature
if (!self.incognitoTabTipBubblePresenter.isUserEngaged) {
__weak BrowserViewController* weakSelf = self;
void (^onInitializedBlock)(bool) = ^(bool successfullyLoaded) {
if (!successfullyLoaded)
return;
[weakSelf presentNewIncognitoTabTipBubble];
};
......
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