123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- // 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.
- #import "ios/chrome/app/safe_mode_app_state_agent.h"
- #include "base/ios/ios_util.h"
- #include "base/version.h"
- #import "ios/chrome/app/application_delegate/app_state.h"
- #import "ios/chrome/app/application_delegate/app_state_observer.h"
- #import "ios/chrome/browser/ui/main/scene_state.h"
- #import "ios/chrome/browser/ui/main/scene_state_observer.h"
- #import "ios/chrome/browser/ui/safe_mode/safe_mode_coordinator.h"
- #import "ios/chrome/browser/ui/scoped_ui_blocker/scoped_ui_blocker.h"
- #if !defined(__has_feature) || !__has_feature(objc_arc)
- #error "This file requires ARC support."
- #endif
- @interface SafeModeAppAgent () <SafeModeCoordinatorDelegate,
- AppStateObserver,
- SceneStateObserver> {
- // Multiwindow UI blocker used when safe mode is active to only show the safe
- // mode UI on one window.
- std::unique_ptr<ScopedUIBlocker> _safeModeBlocker;
- }
- // This flag is set when the first scene has activated since the startup, and
- // never reset.
- @property(nonatomic, assign) BOOL firstSceneHasActivated;
- // The app state the agent is connected to.
- @property(nonatomic, weak, readonly) AppState* appState;
- // Safe mode coordinator. If this is non-nil, the app is displaying the safe
- // mode UI.
- @property(nonatomic, strong) SafeModeCoordinator* safeModeCoordinator;
- @end
- @implementation SafeModeAppAgent
- #pragma mark - AppStateAgent
- - (void)setAppState:(AppState*)appState {
- // This should only be called once!
- DCHECK(!_appState);
- _appState = appState;
- [appState addObserver:self];
- }
- #pragma mark - SafeModeCoordinatorDelegate Implementation
- - (void)coordinatorDidExitSafeMode:(SafeModeCoordinator*)coordinator {
- DCHECK(coordinator);
- [self stopSafeMode];
- // Transition out of Safe Mode init stage to the next stage.
- [self.appState queueTransitionToNextInitStage];
- }
- #pragma mark - SceneStateObserver
- - (void)sceneState:(SceneState*)sceneState
- transitionedToActivationLevel:(SceneActivationLevel)level {
- // Don't try to trigger Safe Mode when the scene is not yet active on the
- // foreground.
- if (level < SceneActivationLevelForegroundActive) {
- return;
- }
- // Don't try to trigger Safe Mode when the app has already passed the safe
- // mode stage when the scene transitions to foreground. If the init stage is
- // still Safe Mode at this moment it means that safe mode has to be triggered.
- if (self.appState.initStage != InitStageSafeMode) {
- return;
- }
- // Don't try to show the safe mode UI on multiple scenes; one scene is
- // sufficient.
- if (self.firstSceneHasActivated) {
- return;
- }
- self.firstSceneHasActivated = YES;
- [self startSafeMode:sceneState];
- }
- #pragma mark - AppStateObserver
- - (void)appState:(AppState*)appState
- didTransitionFromInitStage:(InitStage)previousInitStage {
- if (self.appState.initStage != InitStageSafeMode) {
- return;
- }
- // Iterate further in the init stages when safe mode isn't needed; stop
- // and switch the app to safe mode otherwise.
- if ([SafeModeCoordinator shouldStart]) {
- return;
- }
- [self.appState queueTransitionToNextInitStage];
- }
- - (void)appState:(AppState*)appState sceneConnected:(SceneState*)sceneState {
- [sceneState addObserver:self];
- }
- #pragma mark - Internals
- - (void)startSafeMode:(SceneState*)sceneState {
- DCHECK(sceneState);
- DCHECK(!_safeModeBlocker);
- self.safeModeCoordinator =
- [[SafeModeCoordinator alloc] initWithWindow:sceneState.window];
- self.safeModeCoordinator.delegate = self;
- // Activate the main window, which will prompt the views to load.
- [sceneState.window makeKeyAndVisible];
- [self.safeModeCoordinator start];
- if (base::ios::IsMultipleScenesSupported()) {
- _safeModeBlocker = std::make_unique<ScopedUIBlocker>(sceneState);
- }
- }
- - (void)stopSafeMode {
- if (_safeModeBlocker) {
- _safeModeBlocker.reset();
- }
- self.safeModeCoordinator = nil;
- }
- @end
|