Commit eca462b8 authored by Stepan Khapugin's avatar Stepan Khapugin Committed by Commit Bot

[iOS][Getaway] Implement data plumbing to tab switcher UI.

Adds necessary observation code and plumbing to the tab switcher view
controller to add UI in the future.

Bug: none
Change-Id: I5912042ecf4634b7a8c0b3628b40505293cfcdaa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2536454
Commit-Queue: Stepan Khapugin <stkhapugin@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#830672}
parent 881b5838
......@@ -4,6 +4,19 @@
import("//ios/build/chrome_build.gni")
source_set("incognito_reauth_ui") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"incognito_reauth_view.h",
"incognito_reauth_view.mm",
]
deps = [ "//ios/chrome/common/ui/util" ]
frameworks = [
"UIKit.framework",
"LocalAuthentication.framework",
]
}
source_set("incognito_reauth_scene_agent") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
......
......@@ -7,10 +7,21 @@
#import "ios/chrome/browser/ui/main/scene_state.h"
@class IncognitoReauthSceneAgent;
class PrefRegistrySimple;
class PrefService;
@protocol ReauthenticationProtocol;
@protocol IncognitoReauthObserver <NSObject>
@optional
// Called when the authentication requirement in a given scene might have
// changed.
- (void)reauthAgent:(IncognitoReauthSceneAgent*)agent
didUpdateAuthenticationRequirement:(BOOL)isRequired;
@end
// A scene agent that tracks the incognito authentication status for the current
// scene.
@interface IncognitoReauthSceneAgent : NSObject <SceneAgent>
......@@ -42,6 +53,11 @@ class PrefService;
// authentication attempt. It will be called on main thread, asynchronously.
- (void)authenticateWithCompletion:(void (^)(BOOL))completion;
#pragma mark observation
- (void)addObserver:(id<IncognitoReauthObserver>)observer;
- (void)removeObserver:(id<IncognitoReauthObserver>)observer;
@end
#endif // IOS_CHROME_BROWSER_UI_INCOGNITO_REAUTH_INCOGNITO_REAUTH_SCENE_AGENT_H_
......@@ -5,6 +5,7 @@
#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
#include "base/check.h"
#import "base/ios/crb_protocol_observers.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "ios/chrome/browser/application_context.h"
......@@ -19,6 +20,14 @@
#error "This file requires ARC support."
#endif
@interface IncognitoReauthObserverList
: CRBProtocolObservers <IncognitoReauthObserver>
@end
@implementation IncognitoReauthObserverList
@end
#pragma mark - IncognitoReauthSceneAgent
@interface IncognitoReauthSceneAgent () <SceneStateObserver>
// Scene state this agent serves.
......@@ -30,6 +39,9 @@
// Tracks wether the user authenticated for incognito since last launch.
@property(nonatomic, assign) BOOL authenticatedSinceLastForeground;
// Container for observers.
@property(nonatomic, strong) IncognitoReauthObserverList* observers;
@end
@implementation IncognitoReauthSceneAgent
......@@ -48,14 +60,14 @@
if (self) {
DCHECK(reauthModule);
_reauthModule = reauthModule;
_observers = [IncognitoReauthObserverList
observersWithProtocol:@protocol(IncognitoReauthObserver)];
}
return self;
}
- (BOOL)isAuthenticationRequired {
return base::FeatureList::IsEnabled(kIncognitoAuthentication) &&
[self authEnabledInSettings] &&
self.windowHadIncognitoContentOnForeground &&
return [self featureEnabled] && self.windowHadIncognitoContentOnForeground &&
!self.authenticatedSinceLastForeground;
}
......@@ -87,6 +99,36 @@
}];
}
- (void)addObserver:(id<IncognitoReauthObserver>)observer {
[self.observers addObserver:observer];
}
- (void)removeObserver:(id<IncognitoReauthObserver>)observer {
[self.observers removeObserver:observer];
}
#pragma mark properties
- (void)setAuthenticatedSinceLastForeground:(BOOL)authenticated {
_authenticatedSinceLastForeground = authenticated;
if (self.featureEnabled) {
[self notifyObservers];
}
}
- (void)setWindowHadIncognitoContentOnForeground:(BOOL)hadIncognitoContent {
_windowHadIncognitoContentOnForeground = hadIncognitoContent;
if (self.featureEnabled) {
[self notifyObservers];
}
}
- (void)notifyObservers {
DCHECK(self.featureEnabled);
[self.observers reauthAgent:self
didUpdateAuthenticationRequirement:self.isAuthenticationRequired];
}
#pragma mark - SceneStateObserver
- (void)sceneState:(SceneState*)sceneState
......@@ -119,14 +161,21 @@
- (PrefService*)localState {
if (!_localState) {
if (!GetApplicationContext()) {
// This is called before application context was initialized.
return nil;
}
_localState = GetApplicationContext()->GetLocalState();
}
return _localState;
}
// Convenience method to check the pref associated with the reauth setting.
- (BOOL)authEnabledInSettings {
return self.localState->GetBoolean(prefs::kIncognitoAuthenticationSetting);
// Convenience method to check the pref associated with the reauth setting and
// the feature flag.
- (BOOL)featureEnabled {
return base::FeatureList::IsEnabled(kIncognitoAuthentication) &&
self.localState &&
self.localState->GetBoolean(prefs::kIncognitoAuthenticationSetting);
}
@end
// Copyright 2020 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_UI_INCOGNITO_REAUTH_INCOGNITO_REAUTH_VIEW_H_
#define IOS_CHROME_BROWSER_UI_INCOGNITO_REAUTH_INCOGNITO_REAUTH_VIEW_H_
#import <UIKit/UIKit.h>
// The view that is used to overlay over non-authorized incognito content.
@interface IncognitoReauthView : UIView
// Button that allows biometric authentication.
// Will auto-adjust its string based on the available authentication methods on
// the user's device.
@property(nonatomic, strong, readonly) UIButton* authenticateButton;
// The button to go to the tab switcher.
@property(nonatomic, strong, readonly) UIButton* tabSwitcherButton;
@end
#endif // IOS_CHROME_BROWSER_UI_INCOGNITO_REAUTH_INCOGNITO_REAUTH_VIEW_H_
// Copyright 2020 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/ui/incognito_reauth/incognito_reauth_view.h"
#import <LocalAuthentication/LocalAuthentication.h>
#import "ios/chrome/common/ui/util/constraints_ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
const CGFloat kButtonHeight = 60.0f;
const CGFloat kButtonWidth = 190.0f;
const CGFloat kButtonSpacing = 16.0f;
} // namespace
@implementation IncognitoReauthView
- (instancetype)init {
self = [super init];
if (self) {
UIBlurEffect* blurEffect =
[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
UIVisualEffectView* blurBackgroundView =
[[UIVisualEffectView alloc] initWithEffect:blurEffect];
[self addSubview:blurBackgroundView];
blurBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
AddSameConstraints(self, blurBackgroundView);
_authenticateButton =
[IncognitoReauthView newRoundButtonWithBlurEffect:blurEffect];
[_authenticateButton
setTitle:[IncognitoReauthView authenticationActionLabel]
forState:UIControlStateNormal];
_tabSwitcherButton =
[IncognitoReauthView newRoundButtonWithBlurEffect:blurEffect];
// TODO(crbug.com/1138892): add localized text.
[_tabSwitcherButton setTitle:@"[Test String] Go to Tab Switcher"
forState:UIControlStateNormal];
UIStackView* stackView = [[UIStackView alloc]
initWithArrangedSubviews:@[ _authenticateButton, _tabSwitcherButton ]];
stackView.axis = UILayoutConstraintAxisVertical;
stackView.translatesAutoresizingMaskIntoConstraints = NO;
stackView.spacing = kButtonSpacing;
[self addSubview:stackView];
AddSameCenterConstraints(blurBackgroundView, stackView);
}
return self;
}
+ (NSString*)authenticationActionLabel {
LAContext* ctx = [[LAContext alloc] init];
switch (ctx.biometryType) {
case LABiometryTypeFaceID:
return @"Face ID";
case LABiometryTypeTouchID:
return @"Touch ID";
default:
// TODO(crbug.com/1138892): add localized text.
return @"[Test String] Passcode";
}
}
+ (UIButton*)newRoundButtonWithBlurEffect:(UIBlurEffect*)blurEffect {
UIButton* button = [[UIButton alloc] init];
button.backgroundColor = [UIColor clearColor];
[NSLayoutConstraint activateConstraints:@[
[button.heightAnchor constraintEqualToConstant:kButtonHeight],
[button.widthAnchor constraintEqualToConstant:kButtonWidth],
]];
UIView* backgroundView = nil;
if (@available(iOS 13, *)) {
backgroundView = [[UIVisualEffectView alloc]
initWithEffect:[UIVibrancyEffect
effectForBlurEffect:blurEffect
style:UIVibrancyEffectStyleFill]];
} else {
backgroundView = [[UIView alloc] init];
}
backgroundView.backgroundColor = [UIColor colorWithWhite:1 alpha:0.2];
backgroundView.layer.cornerRadius = kButtonHeight / 2;
backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
[button addSubview:backgroundView];
AddSameConstraints(backgroundView, button);
return button;
}
@end
......@@ -273,12 +273,10 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
// Add agents.
[_sceneState addAgent:[[UIBlockerSceneAgent alloc] init]];
[_sceneState addAgent:[[IncognitoBlockerSceneAgent alloc] init]];
if (base::FeatureList::IsEnabled(kIncognitoAuthentication)) {
[_sceneState
addAgent:[[IncognitoReauthSceneAgent alloc]
initWithReauthModule:[[ReauthenticationModule alloc]
init]]];
}
[_sceneState
addAgent:[[IncognitoReauthSceneAgent alloc]
initWithReauthModule:[[ReauthenticationModule alloc]
init]]];
}
return self;
}
......
......@@ -41,6 +41,7 @@ source_set("tab_grid") {
"//ios/chrome/browser/ui/gestures",
"//ios/chrome/browser/ui/history",
"//ios/chrome/browser/ui/history/public",
"//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent",
"//ios/chrome/browser/ui/main",
"//ios/chrome/browser/ui/recent_tabs",
"//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui",
......@@ -164,6 +165,7 @@ source_set("unit_tests") {
"//ios/chrome/browser/tabs",
"//ios/chrome/browser/tabs:tabs_internal",
"//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/main:scene_state_header",
"//ios/chrome/browser/ui/tab_switcher",
"//ios/chrome/browser/web",
"//ios/chrome/browser/web:page_placeholder",
......
......@@ -53,6 +53,7 @@ source_set("grid_ui") {
"//ios/chrome/browser/ui:feature_flags",
"//ios/chrome/browser/ui/elements",
"//ios/chrome/browser/ui/gestures",
"//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_ui",
"//ios/chrome/browser/ui/tab_switcher",
"//ios/chrome/browser/ui/tab_switcher/tab_grid/transitions",
"//ios/chrome/browser/ui/thumb_strip:feature_flags",
......
......@@ -12,6 +12,10 @@
// Supports idempotent insert/delete/updates to a grid.
@protocol GridConsumer
// Notify consumer that the displayed items require authentication before they
// can be accessed. Used for biometric incognito tab authentication.
- (void)setItemsRequireAuthentication:(BOOL)requireAuthentication;
// Many of the following methods pass a |selectedItemID| as a parameter,
// indicating the identifier of the item that should be in the selected state
// after the method is called. In every such case, a nil |selectedItemID|
......
......@@ -45,6 +45,11 @@
- (void)didChangeLastItemVisibilityInGridViewController:
(GridViewController*)gridViewController;
// Tells the delegate when the currently displayed content is hidden from the
// user until they authenticate. Used for incognito biometric authentication.
- (void)gridViewController:(GridViewController*)gridViewController
contentNeedsAuthenticationChanged:(BOOL)needsAuth;
@end
// A view controller that contains a grid of items.
......@@ -71,6 +76,9 @@
@property(nonatomic, assign) BOOL showsSelectionUpdates;
// The fraction of the last item of the grid that is visible.
@property(nonatomic, assign, readonly) CGFloat fractionVisibleOfLastItem;
// YES when the current contents are hidden from the user before a successful
// biometric authentication.
@property(nonatomic, assign) BOOL contentNeedsAuthentication;
// Returns the layout of the grid for use in an animated transition.
- (GridTransitionLayout*)transitionLayout;
......
......@@ -15,6 +15,7 @@
#import "base/numerics/safe_conversions.h"
#include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
#include "ios/chrome/browser/procedural_block_types.h"
#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_cell.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_drag_drop_handler.h"
......@@ -56,6 +57,9 @@ NSIndexPath* CreateIndexPath(NSInteger index) {
UICollectionViewDropDelegate>
// A collection view of items in a grid format.
@property(nonatomic, weak) UICollectionView* collectionView;
// A view to obscure incognito content when the user isn't authorized to
// see it.
@property(nonatomic, strong) IncognitoReauthView* blockingView;
// The local model backing the collection view.
@property(nonatomic, strong) NSMutableArray<TabSwitcherItem*>* items;
// Identifier of the selected item. This value is disregarded if |self.items| is
......@@ -614,6 +618,27 @@ NSIndexPath* CreateIndexPath(NSInteger index) {
#pragma mark - GridConsumer
- (void)setItemsRequireAuthentication:(BOOL)require {
self.contentNeedsAuthentication = require;
[self.delegate gridViewController:self
contentNeedsAuthenticationChanged:require];
if (require) {
if (!self.blockingView) {
self.blockingView = [[IncognitoReauthView alloc] init];
self.blockingView.translatesAutoresizingMaskIntoConstraints = NO;
self.blockingView.layer.zPosition = FLT_MAX;
// No need to show tab switcher button when already in the tab switcher.
self.blockingView.tabSwitcherButton.hidden = YES;
}
[self.view addSubview:self.blockingView];
AddSameConstraints(self.collectionView.frameLayoutGuide, self.blockingView);
} else {
[self.blockingView removeFromSuperview];
}
}
- (void)populateItems:(NSArray<TabSwitcherItem*>*)items
selectedItemID:(NSString*)selectedItemID {
#ifndef NDEBUG
......
......@@ -31,6 +31,10 @@
@end
@implementation FakeGridViewControllerDelegate
@synthesize itemCount = _itemCount;
- (void)gridViewController:(GridViewController*)gridViewController
contentNeedsAuthenticationChanged:(BOOL)needsAuth {
}
- (void)gridViewController:(GridViewController*)gridViewController
didChangeItemCount:(NSUInteger)count {
self.itemCount = count;
......
......@@ -35,6 +35,8 @@
// Sets target/action for tapping event on new tab button.
- (void)setNewTabButtonTarget:(id)target action:(SEL)action;
// Set |enabled| on the new tab button.
- (void)setNewTabButtonEnabled:(BOOL)enabled;
// Hides components and uses a black background color for tab grid transition
// animation.
......
......@@ -86,6 +86,11 @@
forControlEvents:UIControlEventTouchUpInside];
}
- (void)setNewTabButtonEnabled:(BOOL)enabled {
_smallNewTabButton.enabled = enabled;
_largeNewTabButton.enabled = enabled;
}
- (void)hide {
_smallNewTabButton.alpha = 0.0;
_largeNewTabButton.alpha = 0.0;
......
......@@ -25,7 +25,9 @@
#import "ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.h"
#import "ios/chrome/browser/ui/history/history_coordinator.h"
#import "ios/chrome/browser/ui/history/public/history_presentation_delegate.h"
#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
#import "ios/chrome/browser/ui/main/bvc_container_view_controller.h"
#import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h"
#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.h"
#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h"
......@@ -309,7 +311,8 @@
_baseViewController = baseViewController;
self.regularTabsMediator = [[TabGridMediator alloc]
initWithConsumer:baseViewController.regularTabsConsumer];
initWithConsumer:baseViewController.regularTabsConsumer
reauthAgent:nil];
ChromeBrowserState* regularBrowserState =
_regularBrowser ? _regularBrowser->GetBrowserState() : nullptr;
WebStateList* regularWebStateList =
......@@ -322,8 +325,19 @@
IOSChromeTabRestoreServiceFactory::GetForBrowserState(
regularBrowserState);
}
IncognitoReauthSceneAgent* reauthAgent = nil;
for (id agent in SceneStateBrowserAgent::FromBrowser(_incognitoBrowser)
->GetSceneState()
.connectedAgents) {
if ([agent isKindOfClass:[IncognitoReauthSceneAgent class]]) {
reauthAgent = agent;
}
}
self.incognitoTabsMediator = [[TabGridMediator alloc]
initWithConsumer:baseViewController.incognitoTabsConsumer];
initWithConsumer:baseViewController.incognitoTabsConsumer
reauthAgent:reauthAgent];
self.incognitoTabsMediator.browser = _incognitoBrowser;
self.incognitoTabsMediator.delegate = self;
baseViewController.regularTabsDelegate = self.regularTabsMediator;
......
......@@ -12,6 +12,8 @@
#import "ios/chrome/browser/snapshots/snapshot_browser_agent.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/browsing_data_commands.h"
#import "ios/chrome/browser/ui/main/scene_state.h"
#import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
#include "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator_delegate.h"
#import "ios/chrome/test/block_cleanup_test.h"
#include "ios/web/public/test/web_task_environment.h"
......@@ -22,6 +24,20 @@
#error "This file requires ARC support."
#endif
@interface StubSceneState : SceneState
@end
@implementation StubSceneState {
UIWindow* _window;
}
- (void)setWindow:(UIWindow*)window {
_window = window;
}
- (UIWindow*)window {
return _window;
}
@end
@interface TestTabGridCoordinatorDelegate
: NSObject <TabGridCoordinatorDelegate>
@property(nonatomic) BOOL didEndCalled;
......@@ -42,13 +58,25 @@
namespace {
void AddAgentsToBrowser(Browser* browser, SceneState* scene_state) {
SnapshotBrowserAgent::CreateForBrowser(browser);
SnapshotBrowserAgent::FromBrowser(browser)->SetSessionID(
base::SysNSStringToUTF8([[NSUUID UUID] UUIDString]));
SceneStateBrowserAgent::CreateForBrowser(browser, scene_state);
}
class TabGridCoordinatorTest : public BlockCleanupTest {
public:
TabGridCoordinatorTest() {
scene_state_ = [[StubSceneState alloc] initWithAppState:nil];
scene_state_.window =
[[UIApplication sharedApplication].windows firstObject];
browser_ = std::make_unique<TestBrowser>();
SnapshotBrowserAgent::CreateForBrowser(browser_.get());
SnapshotBrowserAgent::FromBrowser(browser_.get())
->SetSessionID(base::SysNSStringToUTF8([[NSUUID UUID] UUIDString]));
AddAgentsToBrowser(browser_.get(), scene_state_);
incognito_browser_ = std::make_unique<TestBrowser>();
AddAgentsToBrowser(incognito_browser_.get(), scene_state_);
UIWindow* window = [UIApplication sharedApplication].keyWindow;
coordinator_ = [[TabGridCoordinator alloc]
......@@ -58,7 +86,7 @@ class TabGridCoordinatorTest : public BlockCleanupTest {
browsingDataCommandEndpoint:OCMProtocolMock(
@protocol(BrowsingDataCommands))
regularBrowser:browser_.get()
incognitoBrowser:nil];
incognitoBrowser:incognito_browser_.get()];
coordinator_.animationsDisabledForTesting = YES;
// TabGirdCoordinator will make its view controller the root, so stash the
// original root view controller before starting |coordinator_|.
......@@ -93,6 +121,12 @@ class TabGridCoordinatorTest : public BlockCleanupTest {
// Browser for the coordinator.
std::unique_ptr<Browser> browser_;
// Browser for the coordinator.
std::unique_ptr<Browser> incognito_browser_;
// Scene state emulated in this test.
SceneState* scene_state_;
// The TabGridCoordinator that is under test. The test fixture sets
// this VC as the root VC for the window.
TabGridCoordinator* coordinator_;
......
......@@ -13,6 +13,7 @@
class Browser;
@protocol GridConsumer;
@class IncognitoReauthSceneAgent;
@class TabGridMediator;
namespace sessions {
......@@ -47,6 +48,7 @@ class TabRestoreService;
// Initializer with |consumer| as the receiver of model layer updates.
- (instancetype)initWithConsumer:(id<GridConsumer>)consumer
reauthAgent:(IncognitoReauthSceneAgent*)reauthAgent
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
......
......@@ -28,6 +28,7 @@
#import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
#include "ios/chrome/browser/system_flags.h"
#import "ios/chrome/browser/tabs/tab_title_util.h"
#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_consumer.h"
#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_item.h"
#import "ios/chrome/browser/web/tab_id_tab_helper.h"
......@@ -109,6 +110,7 @@ web::WebState* GetWebStateWithId(WebStateList* web_state_list,
} // namespace
@interface TabGridMediator () <CRWWebStateObserver,
IncognitoReauthObserver,
SnapshotCacheObserver,
WebStateListObserving>
// The list from the browser.
......@@ -125,6 +127,8 @@ web::WebState* GetWebStateWithId(WebStateList* web_state_list,
// Short-term cache for grid thumbnails.
@property(nonatomic, strong)
NSMutableDictionary<NSString*, UIImage*>* appearanceCache;
// Agent tracking the authentication status.
@property(nonatomic, weak) IncognitoReauthSceneAgent* reauthAgent;
@end
@implementation TabGridMediator {
......@@ -138,7 +142,8 @@ web::WebState* GetWebStateWithId(WebStateList* web_state_list,
_scopedWebStateObserver;
}
- (instancetype)initWithConsumer:(id<GridConsumer>)consumer {
- (instancetype)initWithConsumer:(id<GridConsumer>)consumer
reauthAgent:(IncognitoReauthSceneAgent*)agent {
if (self = [super init]) {
_consumer = consumer;
_webStateListObserverBridge =
......@@ -152,6 +157,8 @@ web::WebState* GetWebStateWithId(WebStateList* web_state_list,
std::make_unique<ScopedObserver<web::WebState, web::WebStateObserver>>(
_webStateObserverBridge.get());
_appearanceCache = [[NSMutableDictionary alloc] init];
_reauthAgent = agent;
[agent addObserver:self];
}
return self;
}
......@@ -557,6 +564,13 @@ web::WebState* GetWebStateWithId(WebStateList* web_state_list,
[self.appearanceCache removeAllObjects];
}
#pragma mark - IncognitoReauthObserver
- (void)reauthAgent:(IncognitoReauthSceneAgent*)agent
didUpdateAuthenticationRequirement:(BOOL)isRequired {
[self.consumer setItemsRequireAuthentication:isRequired];
}
#pragma mark - Private
// Calls |-populateItems:selectedItemID:| on the consumer.
......@@ -565,6 +579,9 @@ web::WebState* GetWebStateWithId(WebStateList* web_state_list,
[self.consumer populateItems:CreateItems(self.webStateList)
selectedItemID:GetActiveTabId(self.webStateList)];
}
[self.consumer
setItemsRequireAuthentication:self.reauthAgent.authenticationRequired];
}
// Removes |self.syncedClosedTabsCount| most recent entries from the
......
......@@ -161,6 +161,10 @@ std::unique_ptr<KeyedService> BuildFakeTabRestoreService(
@synthesize items = _items;
@synthesize selectedItemID = _selectedItemID;
- (void)setItemsRequireAuthentication:(BOOL)require {
// No-op.
}
- (void)populateItems:(NSArray<TabSwitcherItem*>*)items
selectedItemID:(NSString*)selectedItemID {
self.selectedItemID = selectedItemID;
......@@ -264,7 +268,8 @@ class TabGridMediatorTest : public PlatformTest {
TabIdTabHelper::FromWebState(web_state_list_->GetWebStateAt(1))
->tab_id();
consumer_ = [[FakeConsumer alloc] init];
mediator_ = [[TabGridMediator alloc] initWithConsumer:consumer_];
mediator_ = [[TabGridMediator alloc] initWithConsumer:consumer_
reauthAgent:nil];
mediator_.browser = browser_.get();
mediator_.tabRestoreService = tab_restore_service_;
}
......
......@@ -991,6 +991,15 @@ NSUInteger GetPageIndexFromPage(TabGridPage page) {
[self configureDoneButtonBasedOnPage:self.currentPage];
}
[self configureCloseAllButtonForCurrentPageAndUndoAvailability];
[self configureNewTabButtonBasedOnContentPermissions];
}
- (void)configureNewTabButtonBasedOnContentPermissions {
BOOL allowNewTab =
!((self.currentPage == TabGridPageIncognitoTabs) &&
self.incognitoTabsViewController.contentNeedsAuthentication);
[self.bottomToolbar setNewTabButtonEnabled:allowNewTab];
}
- (void)configureDoneButtonBasedOnPage:(TabGridPage)page {
......@@ -1002,8 +1011,14 @@ NSUInteger GetPageIndexFromPage(TabGridPage page) {
}
// The Done button should have the same behavior as the other buttons on the
// top Toolbar.
self.doneButton.enabled = !gridViewController.gridEmpty &&
self.topToolbar.pageControl.userInteractionEnabled;
BOOL incognitoTabsNeedsAuth =
(self.currentPage == TabGridPageIncognitoTabs &&
self.incognitoTabsViewController.contentNeedsAuthentication);
self.doneButton.enabled =
!gridViewController.gridEmpty &&
self.topToolbar.pageControl.userInteractionEnabled &&
!incognitoTabsNeedsAuth;
}
- (void)configureCloseAllButtonForCurrentPageAndUndoAvailability {
......@@ -1020,8 +1035,14 @@ NSUInteger GetPageIndexFromPage(TabGridPage page) {
// Otherwise setup as a Close All button.
GridViewController* gridViewController =
[self gridViewControllerForPage:self.currentPage];
self.closeAllButton.enabled =
gridViewController == nil ? NO : !gridViewController.gridEmpty;
BOOL enabled =
(gridViewController == nil) ? NO : !gridViewController.gridEmpty;
BOOL incognitoTabsNeedsAuth =
(self.currentPage == TabGridPageIncognitoTabs &&
self.incognitoTabsViewController.contentNeedsAuthentication);
enabled = enabled && !incognitoTabsNeedsAuth;
self.closeAllButton.enabled = enabled;
self.closeAllButton.title =
l10n_util::GetNSString(IDS_IOS_TAB_GRID_CLOSE_ALL_BUTTON);
// Setting the |accessibilityIdentifier| seems to trigger layout, which causes
......@@ -1386,6 +1407,11 @@ NSUInteger GetPageIndexFromPage(TabGridPage page) {
: CGAffineTransformIdentity;
}
- (void)gridViewController:(GridViewController*)gridViewController
contentNeedsAuthenticationChanged:(BOOL)needsAuth {
[self configureButtonsForActiveAndCurrentPage];
}
#pragma mark - Control actions
- (void)doneButtonTapped:(id)sender {
......
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