| // Copyright 2020 The Chromium Authors |
| // 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/main/incognito_blocker_scene_agent.h" |
| |
| #import "base/apple/bundle_locations.h" |
| #import "base/apple/foundation_util.h" |
| #import "base/ios/ios_util.h" |
| |
| @interface IncognitoBlockerSceneAgent () <SceneStateObserver> |
| |
| // Scene to which this agent is attached. |
| // Implements the setter from SceneAgent protocol. |
| @property(nonatomic, weak) SceneState* sceneState; |
| |
| // Interstitial view used to block any incognito tabs after backgrounding. |
| @property(nonatomic, strong) UIView* overlayView; |
| |
| @end |
| |
| @implementation IncognitoBlockerSceneAgent |
| |
| #pragma mark - properties |
| |
| - (UIView*)overlayView { |
| if (!_overlayView) { |
| // Cover the largest area potentially shown in the app switcher, in case |
| // the screenshot is reused in a different orientation or size class. |
| CGRect screenBounds = [[UIScreen mainScreen] bounds]; |
| CGFloat maxDimension = |
| std::max(CGRectGetWidth(screenBounds), CGRectGetHeight(screenBounds)); |
| _overlayView = [[UIView alloc] |
| initWithFrame:CGRectMake(0, 0, maxDimension, maxDimension)]; |
| UIViewController* launchScreenController = |
| [self loadLaunchScreenControllerFromBundle]; |
| [_overlayView addSubview:launchScreenController.view]; |
| _overlayView.autoresizingMask = |
| UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; |
| } |
| |
| return _overlayView; |
| } |
| |
| #pragma mark - SceneAgent |
| |
| - (void)setSceneState:(SceneState*)sceneState { |
| DCHECK(!_sceneState); |
| _sceneState = sceneState; |
| [sceneState addObserver:self]; |
| } |
| |
| #pragma mark - SceneStateObserver |
| |
| - (void)sceneState:(SceneState*)sceneState |
| transitionedToActivationLevel:(SceneActivationLevel)level { |
| if (level == SceneActivationLevelBackground && |
| (sceneState.incognitoContentVisible || sceneState.QRScannerVisible)) { |
| // If the current BVC is incognito, or if we are in the tab switcher and |
| // there are incognito tabs visible, place a full screen view containing |
| // the switcher background to hide any incognito content. |
| [self showOverlay]; |
| } |
| |
| if (level >= SceneActivationLevelForegroundInactive) { |
| [self hideOverlay]; |
| } |
| } |
| |
| #pragma mark - private |
| |
| - (void)showOverlay { |
| NSArray<UIWindow*>* windows = self.sceneState.scene.windows; |
| |
| // Adding `self.overlayView` to sceneState.window won't cover overlay windows |
| // such as fullscreen video. Instead use the topmost window. |
| |
| NSArray<UIWindow*>* sortedWindows = |
| [windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow* w1, |
| UIWindow* w2) { |
| if (w1.windowLevel == w2.windowLevel) { |
| return NSOrderedSame; |
| } |
| return w1.windowLevel < w2.windowLevel ? NSOrderedAscending |
| : NSOrderedDescending; |
| }]; |
| |
| UIWindow* topWindow = sortedWindows.lastObject; |
| [topWindow addSubview:self.overlayView]; |
| } |
| |
| - (void)hideOverlay { |
| if (!self.overlayView) { |
| return; |
| } |
| [self.overlayView removeFromSuperview]; |
| |
| // Get rid of the view to save memory. |
| self.overlayView = nil; |
| } |
| |
| - (UIViewController*)loadLaunchScreenControllerFromBundle { |
| NSBundle* mainBundle = base::apple::FrameworkBundle(); |
| NSArray* topObjects = [mainBundle loadNibNamed:@"LaunchScreen" |
| owner:self |
| options:nil]; |
| UIViewController* launchScreenController = |
| base::apple::ObjCCastStrict<UIViewController>([topObjects lastObject]); |
| launchScreenController.view.autoresizingMask = |
| UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; |
| return launchScreenController; |
| } |
| |
| @end |