Commit 51a608b8 authored by Kurt Horimoto's avatar Kurt Horimoto Committed by Commit Bot

[iOS] Create InfobarBadgeBrowserAgent.

This agent observes the OverlayPresenters at the kInfobarBanner and
kInfobarModal modalities in order to update InfobarBadgeTabHelper state
for infobar overlay UI interaction.  DidShowOverlay() and
DidHideOverlay() are used to update the badge item's presentation
state.

This BrowserAgent performs some ofthe functionality previously
implemented via the InfobarBadgeUIDelegate protocol, which can be
deleted once kInfobarOverlayUI is enabled by default.

This CL also updates FakeOverlayPresentationContext to execute the
presentation callback in ShowOverlayUI().

Bug: 1030357
Change-Id: I153d1a7e7b220587a2582faf29d0942dad6ead2f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1973104
Commit-Queue: Kurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Auto-Submit: Kurt Horimoto <kkhorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#726962}
parent 7c892456
...@@ -50,6 +50,8 @@ source_set("badge_public") { ...@@ -50,6 +50,8 @@ source_set("badge_public") {
source_set("badge") { source_set("badge") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
sources = [ sources = [
"infobar_badge_browser_agent.h",
"infobar_badge_browser_agent.mm",
"infobar_badge_tab_helper.h", "infobar_badge_tab_helper.h",
"infobar_badge_tab_helper.mm", "infobar_badge_tab_helper.mm",
"infobar_badge_tab_helper_delegate.h", "infobar_badge_tab_helper_delegate.h",
...@@ -58,9 +60,13 @@ source_set("badge") { ...@@ -58,9 +60,13 @@ source_set("badge") {
":badge_public", ":badge_public",
":infobars", ":infobars",
":public", ":public",
"//ios/chrome/browser/main:public",
"//ios/chrome/browser/overlays",
"//ios/chrome/browser/overlays/public/common/infobars",
"//ios/chrome/browser/ui/badges:public", "//ios/chrome/browser/ui/badges:public",
"//ios/chrome/browser/ui/infobars:feature_flags", "//ios/chrome/browser/ui/infobars:feature_flags",
"//ios/chrome/browser/ui/infobars:infobars_ui", "//ios/chrome/browser/ui/infobars:infobars_ui",
"//ios/chrome/browser/web_state_list",
"//ios/web", "//ios/web",
] ]
} }
...@@ -84,6 +90,7 @@ source_set("unit_tests") { ...@@ -84,6 +90,7 @@ source_set("unit_tests") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
testonly = true testonly = true
sources = [ sources = [
"infobar_badge_browser_agent_unittest.mm",
"infobar_badge_tab_helper_unittest.mm", "infobar_badge_tab_helper_unittest.mm",
] ]
deps = [ deps = [
...@@ -92,14 +99,23 @@ source_set("unit_tests") { ...@@ -92,14 +99,23 @@ source_set("unit_tests") {
"//base/test:test_support", "//base/test:test_support",
"//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/browser_state:test_support",
"//ios/chrome/browser/infobars:public", "//ios/chrome/browser/infobars:public",
"//ios/chrome/browser/infobars/overlays:test_support",
"//ios/chrome/browser/infobars/test",
"//ios/chrome/browser/main",
"//ios/chrome/browser/main:test_support",
"//ios/chrome/browser/overlays",
"//ios/chrome/browser/overlays/public/common/infobars",
"//ios/chrome/browser/overlays/test",
"//ios/chrome/browser/ui/badges:public", "//ios/chrome/browser/ui/badges:public",
"//ios/chrome/browser/ui/infobars:feature_flags", "//ios/chrome/browser/ui/infobars:feature_flags",
"//ios/chrome/browser/ui/infobars:infobars_ui", "//ios/chrome/browser/ui/infobars:infobars_ui",
"//ios/chrome/browser/ui/infobars:test_support", "//ios/chrome/browser/ui/infobars:test_support",
"//ios/chrome/browser/ui/infobars:test_support",
"//ios/chrome/browser/ui/infobars/coordinators", "//ios/chrome/browser/ui/infobars/coordinators",
"//ios/chrome/browser/ui/infobars/test", "//ios/chrome/browser/ui/infobars/test",
"//ios/chrome/browser/web_state_list",
"//ios/chrome/browser/web_state_list:test_support",
"//ios/chrome/test:test_support", "//ios/chrome/test:test_support",
"//ios/web/public/test",
"//ios/web/public/test/fakes", "//ios/web/public/test/fakes",
"//testing/gtest", "//testing/gtest",
] ]
......
// Copyright 2019 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.
#ifndef IOS_CHROME_BROWSER_INFOBARS_INFOBAR_BADGE_BROWSER_AGENT_H_
#define IOS_CHROME_BROWSER_INFOBARS_INFOBAR_BADGE_BROWSER_AGENT_H_
#include "base/scoped_observer.h"
#import "ios/chrome/browser/infobars/infobar_type.h"
#include "ios/chrome/browser/main/browser_user_data.h"
#include "ios/chrome/browser/overlays/public/overlay_presenter.h"
#include "ios/chrome/browser/overlays/public/overlay_presenter_observer.h"
class InfobarBadgeTabHelper;
namespace web {
class WebState;
}
// Browser agent that updates InfobarTabHelpers for observed infobar overlay
// events.
class InfobarBadgeBrowserAgent
: public BrowserUserData<InfobarBadgeBrowserAgent> {
public:
~InfobarBadgeBrowserAgent() override;
private:
BROWSER_USER_DATA_KEY_DECL();
friend class BrowserUserData<InfobarBadgeBrowserAgent>;
explicit InfobarBadgeBrowserAgent(Browser* browser);
// Returns the badge tab helper for the active WebState.
InfobarBadgeTabHelper* GetBadgeCurrentTabHelper() const;
// Called when the banner UI for |request| was presented or dismissed.
void OnInfobarBannerPresented(OverlayRequest* request);
void OnInfobarBannerDismissed(OverlayRequest* request);
// Helper object that observes the presentation of infobar overlays.
class InfobarOverlayObserver : public OverlayPresenterObserver {
public:
InfobarOverlayObserver(InfobarBadgeBrowserAgent* browser_agent,
Browser* browser);
~InfobarOverlayObserver() override;
private:
// OverlayPresenterObserver:
void DidShowOverlay(OverlayPresenter* presenter,
OverlayRequest* request) override;
void DidHideOverlay(OverlayPresenter* presenter,
OverlayRequest* request) override;
void OverlayPresenterDestroyed(OverlayPresenter* presenter) override;
private:
ScopedObserver<OverlayPresenter, OverlayPresenterObserver> scoped_observer_;
InfobarBadgeBrowserAgent* browser_agent_;
};
InfobarOverlayObserver infobar_overlay_observer_;
WebStateList* web_state_list_ = nullptr;
};
#endif // IOS_CHROME_BROWSER_INFOBARS_INFOBAR_BADGE_BROWSER_AGENT_H_
// Copyright 2019 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.
#import "ios/chrome/browser/infobars/infobar_badge_browser_agent.h"
#include "base/logging.h"
#include "ios/chrome/browser/infobars/infobar_badge_tab_helper.h"
#import "ios/chrome/browser/overlays/public/common/infobars/infobar_overlay_request_config.h"
#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h"
#include "ios/chrome/browser/overlays/public/overlay_presenter.h"
#include "ios/chrome/browser/overlays/public/overlay_request.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Returns the InfobarType used to configure |request|. |request| must be
// configured with an InfobarOverlayRequestConfig.
InfobarType GetInfobarType(OverlayRequest* request) {
return request->GetConfig<InfobarOverlayRequestConfig>()->infobar_type();
}
} // namespace
#pragma mark - InfobarBadgeBrowserAgent
BROWSER_USER_DATA_KEY_IMPL(InfobarBadgeBrowserAgent)
InfobarBadgeBrowserAgent::InfobarBadgeBrowserAgent(Browser* browser)
: infobar_overlay_observer_(this, browser),
web_state_list_(browser->GetWebStateList()) {
DCHECK(web_state_list_);
}
InfobarBadgeBrowserAgent::~InfobarBadgeBrowserAgent() = default;
InfobarBadgeTabHelper* InfobarBadgeBrowserAgent::GetBadgeCurrentTabHelper()
const {
if (web_state_list_->active_index() == WebStateList::kInvalidIndex)
return nullptr;
return InfobarBadgeTabHelper::FromWebState(
web_state_list_->GetActiveWebState());
}
void InfobarBadgeBrowserAgent::OnInfobarBannerPresented(
OverlayRequest* request) {
InfobarBadgeTabHelper* tab_helper = GetBadgeCurrentTabHelper();
if (tab_helper)
tab_helper->UpdateBadgeForInfobarBannerPresented(GetInfobarType(request));
}
void InfobarBadgeBrowserAgent::OnInfobarBannerDismissed(
OverlayRequest* request) {
InfobarBadgeTabHelper* tab_helper = GetBadgeCurrentTabHelper();
if (tab_helper)
tab_helper->UpdateBadgeForInfobarBannerDismissed(GetInfobarType(request));
}
#pragma mark - InfobarBadgeBrowserAgent::InfobarOverlayObserver
InfobarBadgeBrowserAgent::InfobarOverlayObserver::InfobarOverlayObserver(
InfobarBadgeBrowserAgent* browser_agent,
Browser* browser)
: scoped_observer_(this), browser_agent_(browser_agent) {
DCHECK(browser_agent_);
scoped_observer_.Add(
OverlayPresenter::FromBrowser(browser, OverlayModality::kInfobarBanner));
scoped_observer_.Add(
OverlayPresenter::FromBrowser(browser, OverlayModality::kInfobarModal));
}
InfobarBadgeBrowserAgent::InfobarOverlayObserver::~InfobarOverlayObserver() =
default;
void InfobarBadgeBrowserAgent::InfobarOverlayObserver::DidShowOverlay(
OverlayPresenter* presenter,
OverlayRequest* request) {
browser_agent_->OnInfobarBannerPresented(request);
}
void InfobarBadgeBrowserAgent::InfobarOverlayObserver::DidHideOverlay(
OverlayPresenter* presenter,
OverlayRequest* request) {
browser_agent_->OnInfobarBannerDismissed(request);
}
void InfobarBadgeBrowserAgent::InfobarOverlayObserver::
OverlayPresenterDestroyed(OverlayPresenter* presenter) {
scoped_observer_.Remove(presenter);
}
// Copyright 2019 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.
#import "ios/chrome/browser/infobars/infobar_badge_browser_agent.h"
#import <Foundation/Foundation.h>
#include <map>
#include "base/test/scoped_feature_list.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#include "ios/chrome/browser/infobars/infobar_badge_tab_helper.h"
#include "ios/chrome/browser/infobars/infobar_badge_tab_helper_delegate.h"
#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
#import "ios/chrome/browser/infobars/overlays/fake_infobar_overlay_request_factory.h"
#import "ios/chrome/browser/infobars/test/fake_infobar_ios.h"
#import "ios/chrome/browser/main/test_browser.h"
#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h"
#include "ios/chrome/browser/overlays/public/overlay_request.h"
#import "ios/chrome/browser/overlays/public/overlay_request_queue.h"
#include "ios/chrome/browser/overlays/public/overlay_response.h"
#include "ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h"
#import "ios/chrome/browser/ui/badges/badge_item.h"
#import "ios/chrome/browser/ui/badges/badge_type.h"
#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
#import "ios/chrome/browser/ui/infobars/test/fake_infobar_ui_delegate.h"
#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/browser/web_state_list/web_state_opener.h"
#import "ios/web/public/test/fakes/test_navigation_manager.h"
#import "ios/web/public/test/fakes/test_web_state.h"
#include "ios/web/public/test/web_task_environment.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using infobars::InfoBar;
namespace {
// The InfobarType to use for the test.
const InfobarType kInfobarType = InfobarType::kInfobarTypePasswordSave;
// The BadgeType used for the test.
const BadgeType kBadgeType = BadgeType::kBadgeTypePasswordSave;
} // namespace
#pragma mark - FakeInfobarTabHelperDelegate
// Fake version of InfobarTabHelperDelegate to use in tests.
@interface FakeInfobarTabHelperDelegate
: NSObject <InfobarBadgeTabHelperDelegate> {
std::map<BadgeType, id<BadgeItem>> _badgeItems;
}
- (id<BadgeItem>)itemForBadgeType:(BadgeType)type;
@end
@implementation FakeInfobarTabHelperDelegate
- (void)addInfobarBadge:(id<BadgeItem>)badgeItem {
_badgeItems[badgeItem.badgeType] = badgeItem;
}
- (void)removeInfobarBadge:(id<BadgeItem>)badgeItem {
_badgeItems[badgeItem.badgeType] = nil;
}
- (void)updateInfobarBadge:(id<BadgeItem>)badgeItem {
}
- (id<BadgeItem>)itemForBadgeType:(BadgeType)type {
return _badgeItems[type];
}
@end
#pragma mark - InfobarBadgeBrowserAgentTest
// Test fixture for InfobarBadgeBrowserAgent.
class InfobarBadgeBrowserAgentTest : public PlatformTest {
public:
InfobarBadgeBrowserAgentTest()
: web_state_list_(&web_state_list_delegate_),
tab_helper_delegate_([[FakeInfobarTabHelperDelegate alloc] init]) {
// Enable the UI reboot feature.
feature_list_.InitAndEnableFeature(kInfobarUIReboot);
// Create the Browser and set up the browser agent.
TestChromeBrowserState::Builder builder;
browser_state_ = builder.Build();
browser_ =
std::make_unique<TestBrowser>(browser_state_.get(), &web_state_list_);
InfobarBadgeBrowserAgent::CreateForBrowser(browser_.get());
// Create a WebState and add it to the Browser.
std::unique_ptr<web::TestWebState> passed_web_state =
std::make_unique<web::TestWebState>();
passed_web_state->SetNavigationManager(
std::make_unique<web::TestNavigationManager>());
web_state_ = passed_web_state.get();
web_state_list_.InsertWebState(0, std::move(passed_web_state),
WebStateList::INSERT_ACTIVATE,
WebStateOpener());
// Set up the WebState's InfoBarManager and InfobarBadgeTabHelper.
InfoBarManagerImpl::CreateForWebState(web_state_);
InfobarBadgeTabHelper::CreateForWebState(web_state_);
InfobarBadgeTabHelper::FromWebState(web_state_)
->SetDelegate(tab_helper_delegate_);
// Set up the OverlayPresenter for OverlayModality::kInfobarBanner.
presenter()->SetPresentationContext(&presentation_context_);
}
~InfobarBadgeBrowserAgentTest() override {
presenter()->SetPresentationContext(nullptr);
}
// Adds an InfoBar with |type| to the manager and returns the added infobar.
InfoBar* AddInfobar() {
std::unique_ptr<FakeInfobarIOS> passed_infobar =
std::make_unique<FakeInfobarIOS>();
InfoBar* infobar = passed_infobar.get();
passed_infobar->fake_ui_delegate().infobarType = kInfobarType;
passed_infobar->fake_ui_delegate().hasBadge = YES;
InfoBarManagerImpl::FromWebState(web_state_)
->AddInfoBar(std::move(passed_infobar));
return infobar;
}
// Adds a fake banner OverlayRequest for |infobar|, adds it to queue(), and
// returns the added request.
OverlayRequest* AddOverlayRequest(InfoBar* infobar) {
FakeInfobarOverlayRequestFactory factory;
std::unique_ptr<OverlayRequest> passed_request =
factory.CreateInfobarRequest(infobar, InfobarOverlayType::kBanner);
OverlayRequest* request = passed_request.get();
queue()->AddRequest(std::move(passed_request));
return request;
}
OverlayPresenter* presenter() const {
return OverlayPresenter::FromBrowser(browser_.get(),
OverlayModality::kInfobarBanner);
}
OverlayRequestQueue* queue() const {
return OverlayRequestQueue::FromWebState(web_state_,
OverlayModality::kInfobarBanner);
}
protected:
base::test::ScopedFeatureList feature_list_;
web::WebTaskEnvironment task_environment_;
std::unique_ptr<ios::ChromeBrowserState> browser_state_;
FakeWebStateListDelegate web_state_list_delegate_;
WebStateList web_state_list_;
web::WebState* web_state_ = nullptr;
std::unique_ptr<Browser> browser_;
FakeOverlayPresentationContext presentation_context_;
FakeInfobarTabHelperDelegate* tab_helper_delegate_ = nil;
};
// Tests that the browser agent correctly updates the badge state to presented.
TEST_F(InfobarBadgeBrowserAgentTest, InfobarPresented) {
// Simulate the presentation of an infobar banner overlay and verify that the
// badge state gets updated to presented.
InfoBar* infobar = AddInfobar();
OverlayRequest* request = AddOverlayRequest(infobar);
id<BadgeItem> badge = [tab_helper_delegate_ itemForBadgeType:kBadgeType];
ASSERT_TRUE(badge);
ASSERT_EQ(FakeOverlayPresentationContext::PresentationState::kPresented,
presentation_context_.GetPresentationState(request));
EXPECT_TRUE(badge.badgeState & BadgeStatePresented);
}
// Tests that the browser agent correctly updates the badge state to dismissed.
TEST_F(InfobarBadgeBrowserAgentTest, InfobarDismissed) {
InfoBar* infobar = AddInfobar();
OverlayRequest* request = AddOverlayRequest(infobar);
id<BadgeItem> badge = [tab_helper_delegate_ itemForBadgeType:kBadgeType];
ASSERT_TRUE(badge);
ASSERT_EQ(FakeOverlayPresentationContext::PresentationState::kPresented,
presentation_context_.GetPresentationState(request));
ASSERT_TRUE(badge.badgeState & BadgeStatePresented);
// Simulate the dismissal of the infobar banner overlay and verify that the
// badge state gets updated to dismissed.
presentation_context_.SimulateDismissalForRequest(
request, OverlayDismissalReason::kUserInteraction);
EXPECT_FALSE(badge.badgeState & BadgeStatePresented);
}
// TODO(crbug.com/1030357): Add tests for non-banners.
...@@ -36,6 +36,7 @@ source_set("main") { ...@@ -36,6 +36,7 @@ source_set("main") {
"//ios/chrome/browser/sessions:session_service", "//ios/chrome/browser/sessions:session_service",
"//ios/chrome/browser/tabs", "//ios/chrome/browser/tabs",
"//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/infobars:feature_flags",
"//ios/chrome/browser/web_state_list", "//ios/chrome/browser/web_state_list",
] ]
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#import "ios/chrome/browser/main/browser_agent_util.h" #import "ios/chrome/browser/main/browser_agent_util.h"
#include "base/feature_list.h"
#import "ios/chrome/browser/infobars/infobar_badge_browser_agent.h"
#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
#import "ios/chrome/browser/web_state_list/tab_insertion_browser_agent.h" #import "ios/chrome/browser/web_state_list/tab_insertion_browser_agent.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
...@@ -12,4 +15,8 @@ ...@@ -12,4 +15,8 @@
void AttachBrowserAgents(Browser* browser) { void AttachBrowserAgents(Browser* browser) {
TabInsertionBrowserAgent::CreateForBrowser(browser); TabInsertionBrowserAgent::CreateForBrowser(browser);
if (base::FeatureList::IsEnabled(kInfobarOverlayUI)) {
InfobarBadgeBrowserAgent::CreateForBrowser(browser);
}
} }
...@@ -16,8 +16,6 @@ source_set("infobars") { ...@@ -16,8 +16,6 @@ source_set("infobars") {
"//base", "//base",
"//components/infobars/core", "//components/infobars/core",
"//ios/chrome/browser/infobars", "//ios/chrome/browser/infobars",
"//ios/chrome/browser/infobars",
"//ios/chrome/browser/infobars:public",
"//ios/chrome/browser/infobars:public", "//ios/chrome/browser/infobars:public",
"//ios/chrome/browser/overlays", "//ios/chrome/browser/overlays",
"//ios/chrome/browser/ui/infobars:infobars_ui", "//ios/chrome/browser/ui/infobars:infobars_ui",
......
...@@ -85,8 +85,8 @@ void FakeOverlayPresentationContext::ShowOverlayUI( ...@@ -85,8 +85,8 @@ void FakeOverlayPresentationContext::ShowOverlayUI(
OverlayDismissalCallback dismissal_callback) { OverlayDismissalCallback dismissal_callback) {
FakeUIState& state = states_[request]; FakeUIState& state = states_[request];
state.presentation_state = PresentationState::kPresented; state.presentation_state = PresentationState::kPresented;
state.presentation_callback = std::move(presentation_callback);
state.dismissal_callback = std::move(dismissal_callback); state.dismissal_callback = std::move(dismissal_callback);
std::move(presentation_callback).Run();
} }
void FakeOverlayPresentationContext::HideOverlayUI(OverlayPresenter* presenter, void FakeOverlayPresentationContext::HideOverlayUI(OverlayPresenter* presenter,
......
...@@ -63,7 +63,6 @@ class FakeOverlayPresentationContext : public OverlayPresentationContext { ...@@ -63,7 +63,6 @@ class FakeOverlayPresentationContext : public OverlayPresentationContext {
~FakeUIState(); ~FakeUIState();
PresentationState presentation_state = PresentationState::kNotPresented; PresentationState presentation_state = PresentationState::kNotPresented;
OverlayPresentationCallback presentation_callback;
OverlayDismissalCallback dismissal_callback; OverlayDismissalCallback dismissal_callback;
}; };
......
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