1// Copyright 2018 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "ios/chrome/browser/ui/browser_view/browser_coordinator.h" 6 7#include <memory> 8 9#include "base/scoped_observer.h" 10#import "ios/chrome/browser/app_launcher/app_launcher_abuse_detector.h" 11#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h" 12#import "ios/chrome/browser/autofill/autofill_tab_helper.h" 13#include "ios/chrome/browser/browser_state/chrome_browser_state.h" 14#include "ios/chrome/browser/chrome_url_constants.h" 15#include "ios/chrome/browser/download/download_directory_util.h" 16#import "ios/chrome/browser/download/external_app_util.h" 17#import "ios/chrome/browser/download/pass_kit_tab_helper.h" 18#import "ios/chrome/browser/find_in_page/find_tab_helper.h" 19#import "ios/chrome/browser/main/browser.h" 20#import "ios/chrome/browser/store_kit/store_kit_coordinator.h" 21#import "ios/chrome/browser/store_kit/store_kit_tab_helper.h" 22#import "ios/chrome/browser/tabs/tab_title_util.h" 23#import "ios/chrome/browser/ui/activity_services/activity_params.h" 24#import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" 25#import "ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h" 26#import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h" 27#import "ios/chrome/browser/ui/badges/badge_popup_menu_coordinator.h" 28#import "ios/chrome/browser/ui/browser_container/browser_container_coordinator.h" 29#import "ios/chrome/browser/ui/browser_view/browser_view_controller+private.h" 30#import "ios/chrome/browser/ui/browser_view/browser_view_controller.h" 31#import "ios/chrome/browser/ui/browser_view/browser_view_controller_dependency_factory.h" 32#import "ios/chrome/browser/ui/commands/activity_service_commands.h" 33#import "ios/chrome/browser/ui/commands/application_commands.h" 34#import "ios/chrome/browser/ui/commands/browser_coordinator_commands.h" 35#import "ios/chrome/browser/ui/commands/command_dispatcher.h" 36#import "ios/chrome/browser/ui/commands/find_in_page_commands.h" 37#import "ios/chrome/browser/ui/commands/infobar_commands.h" 38#import "ios/chrome/browser/ui/commands/page_info_commands.h" 39#import "ios/chrome/browser/ui/commands/password_breach_commands.h" 40#import "ios/chrome/browser/ui/commands/qr_generation_commands.h" 41#import "ios/chrome/browser/ui/commands/share_highlight_command.h" 42#import "ios/chrome/browser/ui/commands/text_zoom_commands.h" 43#import "ios/chrome/browser/ui/commands/whats_new_commands.h" 44#import "ios/chrome/browser/ui/download/ar_quick_look_coordinator.h" 45#import "ios/chrome/browser/ui/download/pass_kit_coordinator.h" 46#import "ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h" 47#import "ios/chrome/browser/ui/find_bar/find_bar_coordinator.h" 48#import "ios/chrome/browser/ui/infobars/infobar_feature.h" 49#import "ios/chrome/browser/ui/open_in/open_in_mediator.h" 50#import "ios/chrome/browser/ui/overlays/overlay_container_coordinator.h" 51#import "ios/chrome/browser/ui/page_info/features.h" 52#import "ios/chrome/browser/ui/page_info/page_info_coordinator.h" 53#import "ios/chrome/browser/ui/page_info/page_info_legacy_coordinator.h" 54#import "ios/chrome/browser/ui/passwords/password_breach_coordinator.h" 55#import "ios/chrome/browser/ui/print/print_controller.h" 56#import "ios/chrome/browser/ui/qr_generator/qr_generator_coordinator.h" 57#import "ios/chrome/browser/ui/qr_scanner/qr_scanner_legacy_coordinator.h" 58#import "ios/chrome/browser/ui/reading_list/reading_list_coordinator.h" 59#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.h" 60#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.h" 61#import "ios/chrome/browser/ui/sharing/sharing_coordinator.h" 62#import "ios/chrome/browser/ui/snackbar/snackbar_coordinator.h" 63#import "ios/chrome/browser/ui/text_zoom/text_zoom_coordinator.h" 64#import "ios/chrome/browser/ui/toolbar/accessory/toolbar_accessory_coordinator_delegate.h" 65#import "ios/chrome/browser/ui/toolbar/accessory/toolbar_accessory_presenter.h" 66#import "ios/chrome/browser/ui/translate/legacy_translate_infobar_coordinator.h" 67#include "ios/chrome/browser/ui/ui_feature_flags.h" 68#import "ios/chrome/browser/ui/whats_new/default_browser_promo_coordinator.h" 69#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h" 70#import "ios/chrome/browser/url_loading/url_loading_params.h" 71#import "ios/chrome/browser/web/features.h" 72#import "ios/chrome/browser/web/font_size_tab_helper.h" 73#import "ios/chrome/browser/web/print_tab_helper.h" 74#import "ios/chrome/browser/web/repost_form_tab_helper.h" 75#import "ios/chrome/browser/web/repost_form_tab_helper_delegate.h" 76#include "ios/chrome/browser/web_state_list/web_state_list.h" 77#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" 78#include "ui/base/l10n/l10n_util_mac.h" 79 80#if !defined(__has_feature) || !__has_feature(objc_arc) 81#error "This file requires ARC support." 82#endif 83 84@interface BrowserCoordinator () <ActivityServiceCommands, 85 BrowserCoordinatorCommands, 86 DefaultBrowserPromoCommands, 87 FormInputAccessoryCoordinatorNavigator, 88 PageInfoCommands, 89 PasswordBreachCommands, 90 RepostFormTabHelperDelegate, 91 ToolbarAccessoryCoordinatorDelegate, 92 URLLoadingDelegate, 93 WebStateListObserving> 94 95// Whether the coordinator is started. 96@property(nonatomic, assign, getter=isStarted) BOOL started; 97 98// Handles command dispatching, provided by the Browser instance. 99@property(nonatomic, weak) CommandDispatcher* dispatcher; 100 101// The coordinator managing the container view controller. 102@property(nonatomic, strong) 103 BrowserContainerCoordinator* browserContainerCoordinator; 104 105// Mediator between OpenIn TabHelper and OpenIn UI. 106@property(nonatomic, strong) OpenInMediator* openInMediator; 107 108// ================================================= 109// Child Coordinators, listed in alphabetical order. 110// ================================================= 111 112// Presents a QLPreviewController in order to display USDZ format 3D models. 113@property(nonatomic, strong) ARQuickLookCoordinator* ARQuickLookCoordinator; 114 115// Coordinator to add new credit card. 116@property(nonatomic, strong) 117 AutofillAddCreditCardCoordinator* addCreditCardCoordinator; 118 119// Coordinator for the badge popup menu. 120@property(nonatomic, strong) 121 BadgePopupMenuCoordinator* badgePopupMenuCoordinator; 122 123// Coordinator for the find bar. 124@property(nonatomic, strong) FindBarCoordinator* findBarCoordinator; 125 126// Coordinator in charge of the presenting autofill options above the 127// keyboard. 128@property(nonatomic, strong) 129 FormInputAccessoryCoordinator* formInputAccessoryCoordinator; 130 131// Weak reference for the next coordinator to be displayed over the toolbar. 132@property(nonatomic, weak) ChromeCoordinator* nextToolbarCoordinator; 133 134// Coordinator for Page Info UI. 135@property(nonatomic, strong) ChromeCoordinator* pageInfoCoordinator; 136 137// Coordinator for the PassKit UI presentation. 138@property(nonatomic, strong) PassKitCoordinator* passKitCoordinator; 139 140// Coordinator for the password breach UI presentation. 141@property(nonatomic, strong) 142 PasswordBreachCoordinator* passwordBreachCoordinator; 143 144// Used to display the Print UI. Nil if not visible. 145// TODO(crbug.com/910017): Convert to coordinator. 146@property(nonatomic, strong) PrintController* printController; 147 148// Coordinator for the QR scanner. 149@property(nonatomic, strong) QRScannerLegacyCoordinator* qrScannerCoordinator; 150 151// Coordinator for displaying the Reading List. 152@property(nonatomic, strong) ReadingListCoordinator* readingListCoordinator; 153 154// Coordinator for Recent Tabs. 155@property(nonatomic, strong) RecentTabsCoordinator* recentTabsCoordinator; 156 157// Coordinator for displaying Repost Form dialog. 158@property(nonatomic, strong) RepostFormCoordinator* repostFormCoordinator; 159 160// Coordinator for sharing scenarios. 161@property(nonatomic, strong) SharingCoordinator* sharingCoordinator; 162 163// Coordinator for displaying snackbars. 164@property(nonatomic, strong) SnackbarCoordinator* snackbarCoordinator; 165 166// Coordinator for presenting SKStoreProductViewController. 167@property(nonatomic, strong) StoreKitCoordinator* storeKitCoordinator; 168 169// Coordinator for Text Zoom. 170@property(nonatomic, strong) TextZoomCoordinator* textZoomCoordinator; 171 172// Coordinator for the translate infobar's language selection and translate 173// option popup menus. 174@property(nonatomic, strong) 175 LegacyTranslateInfobarCoordinator* translateInfobarCoordinator; 176 177// Coordinator that manages the default browser promo modal. 178@property(nonatomic, strong) 179 DefaultBrowserPromoCoordinator* defaultBrowserPromoCoordinator; 180 181// The container coordinators for the infobar modalities. 182@property(nonatomic, strong) 183 OverlayContainerCoordinator* infobarBannerOverlayContainerCoordinator; 184@property(nonatomic, strong) 185 OverlayContainerCoordinator* infobarModalOverlayContainerCoordinator; 186 187@end 188 189@implementation BrowserCoordinator { 190 // Observers for WebStateList. 191 std::unique_ptr<WebStateListObserverBridge> _webStateListObserverBridge; 192 std::unique_ptr<ScopedObserver<WebStateList, WebStateListObserver>> 193 _scopedWebStateListObserver; 194} 195 196#pragma mark - ChromeCoordinator 197 198- (instancetype)initWithBaseViewController:(UIViewController*)viewController 199 browser:(Browser*)browser { 200 if (self = [super initWithBaseViewController:viewController 201 browser:browser]) { 202 _dispatcher = browser->GetCommandDispatcher(); 203 } 204 return self; 205} 206- (void)start { 207 if (self.started) 208 return; 209 210 DCHECK(!self.viewController); 211 212 // Add commands protocols handled by this class in this array to let the 213 // dispatcher know where to dispatch such commands. This must be done before 214 // starting any child coordinator, otherwise they won't be able to resolve 215 // handlers. 216 NSArray<Protocol*>* protocols = @[ 217 @protocol(ActivityServiceCommands), @protocol(BrowserCoordinatorCommands), 218 @protocol(FindInPageCommands), @protocol(PageInfoCommands), 219 @protocol(PasswordBreachCommands), @protocol(TextZoomCommands), 220 @protocol(WhatsNewCommands) 221 ]; 222 223 for (Protocol* protocol in protocols) { 224 [self.dispatcher startDispatchingToTarget:self forProtocol:protocol]; 225 } 226 227 [self startBrowserContainer]; 228 [self createViewController]; 229 [self startChildCoordinators]; 230 [self installDelegatesForAllWebStates]; 231 [self installDelegatesForBrowser]; 232 [self addWebStateListObserver]; 233 [super start]; 234 self.started = YES; 235} 236 237- (void)stop { 238 if (!self.started) 239 return; 240 [super stop]; 241 [self removeWebStateListObserver]; 242 [self uninstallDelegatesForBrowser]; 243 [self uninstallDelegatesForAllWebStates]; 244 self.viewController.commandDispatcher = nil; 245 [self.dispatcher stopDispatchingToTarget:self]; 246 [self stopChildCoordinators]; 247 [self destroyViewController]; 248 [self stopBrowserContainer]; 249 self.dispatcher = nil; 250 self.started = NO; 251} 252 253#pragma mark - Public 254 255- (void)setActive:(BOOL)active { 256 DCHECK_EQ(_active, self.viewController.active); 257 if (_active == active) { 258 return; 259 } 260 _active = active; 261 262 self.viewController.active = active; 263} 264 265- (void)clearPresentedStateWithCompletion:(ProceduralBlock)completion 266 dismissOmnibox:(BOOL)dismissOmnibox { 267 [self.passKitCoordinator stop]; 268 269 [self.openInMediator disableAll]; 270 271 [self.printController dismissAnimated:YES]; 272 273 [self.readingListCoordinator stop]; 274 self.readingListCoordinator = nil; 275 276 [self.sharingCoordinator stop]; 277 self.sharingCoordinator = nil; 278 279 [self.passwordBreachCoordinator stop]; 280 self.passwordBreachCoordinator = nil; 281 282 [self.pageInfoCoordinator stop]; 283 284 [self.viewController clearPresentedStateWithCompletion:completion 285 dismissOmnibox:dismissOmnibox]; 286} 287 288- (void)displayPopupMenuWithBadgeItems:(NSArray<id<BadgeItem>>*)badgeItems { 289 self.badgePopupMenuCoordinator = [[BadgePopupMenuCoordinator alloc] 290 initWithBaseViewController:self.viewController 291 browser:self.browser]; 292 [self.badgePopupMenuCoordinator setBadgeItemsToShow:badgeItems]; 293 [self.badgePopupMenuCoordinator start]; 294} 295 296#pragma mark - Private 297 298// Instantiates a BrowserViewController. 299- (void)createViewController { 300 DCHECK(self.browserContainerCoordinator.viewController); 301 BrowserViewControllerDependencyFactory* factory = 302 [[BrowserViewControllerDependencyFactory alloc] 303 initWithBrowser:self.browser]; 304 _viewController = [[BrowserViewController alloc] 305 initWithBrowser:self.browser 306 dependencyFactory:factory 307 browserContainerViewController:self.browserContainerCoordinator 308 .viewController 309 dispatcher:self.dispatcher]; 310} 311 312// Shuts down the BrowserViewController. 313- (void)destroyViewController { 314 [self.viewController shutdown]; 315 _viewController = nil; 316} 317 318// Starts the browser container. 319- (void)startBrowserContainer { 320 self.browserContainerCoordinator = [[BrowserContainerCoordinator alloc] 321 initWithBaseViewController:nil 322 browser:self.browser]; 323 [self.browserContainerCoordinator start]; 324} 325 326// Stops the browser container. 327- (void)stopBrowserContainer { 328 [self.browserContainerCoordinator stop]; 329 self.browserContainerCoordinator = nil; 330} 331 332// Starts child coordinators. 333- (void)startChildCoordinators { 334 // Dispatcher should be instantiated so that it can be passed to child 335 // coordinators. 336 DCHECK(self.dispatcher); 337 338 self.ARQuickLookCoordinator = [[ARQuickLookCoordinator alloc] 339 initWithBaseViewController:self.viewController 340 browser:self.browser]; 341 [self.ARQuickLookCoordinator start]; 342 343 self.formInputAccessoryCoordinator = [[FormInputAccessoryCoordinator alloc] 344 initWithBaseViewController:self.viewController 345 browser:self.browser]; 346 self.formInputAccessoryCoordinator.navigator = self; 347 [self.formInputAccessoryCoordinator start]; 348 349 self.snackbarCoordinator = [[SnackbarCoordinator alloc] 350 initWithBaseViewController:self.viewController 351 browser:self.browser]; 352 [self.snackbarCoordinator start]; 353 354 self.translateInfobarCoordinator = [[LegacyTranslateInfobarCoordinator alloc] 355 initWithBaseViewController:self.viewController 356 browser:self.browser]; 357 [self.translateInfobarCoordinator start]; 358 359 self.passKitCoordinator = 360 [[PassKitCoordinator alloc] initWithBaseViewController:self.viewController 361 browser:self.browser]; 362 363 self.printController = [[PrintController alloc] init]; 364 self.printController.baseViewController = self.viewController; 365 366 self.qrScannerCoordinator = [[QRScannerLegacyCoordinator alloc] 367 initWithBaseViewController:self.viewController 368 browser:self.browser]; 369 [self.qrScannerCoordinator start]; 370 371 /* passwordBreachCoordinator is created and started by a BrowserCommand */ 372 373 /* ReadingListCoordinator is created and started by a BrowserCommand */ 374 375 /* RecentTabsCoordinator is created and started by a BrowserCommand */ 376 377 /* RepostFormCoordinator is created and started by a delegate method */ 378 379 /* SharingCoordinator is created and started by an ActivityServiceCommand */ 380 381 self.storeKitCoordinator = [[StoreKitCoordinator alloc] 382 initWithBaseViewController:self.viewController 383 browser:self.browser]; 384 385 self.addCreditCardCoordinator = [[AutofillAddCreditCardCoordinator alloc] 386 initWithBaseViewController:self.viewController 387 browser:self.browser]; 388 389 if (base::FeatureList::IsEnabled(kInfobarOverlayUI)) { 390 self.infobarBannerOverlayContainerCoordinator = 391 [[OverlayContainerCoordinator alloc] 392 initWithBaseViewController:self.viewController 393 browser:self.browser 394 modality:OverlayModality::kInfobarBanner]; 395 [self.infobarBannerOverlayContainerCoordinator start]; 396 self.viewController.infobarBannerOverlayContainerViewController = 397 self.infobarBannerOverlayContainerCoordinator.viewController; 398 399 self.infobarModalOverlayContainerCoordinator = 400 [[OverlayContainerCoordinator alloc] 401 initWithBaseViewController:self.viewController 402 browser:self.browser 403 modality:OverlayModality::kInfobarModal]; 404 [self.infobarModalOverlayContainerCoordinator start]; 405 self.viewController.infobarModalOverlayContainerViewController = 406 self.infobarModalOverlayContainerCoordinator.viewController; 407 } 408} 409 410// Stops child coordinators. 411- (void)stopChildCoordinators { 412 [self.ARQuickLookCoordinator stop]; 413 self.ARQuickLookCoordinator = nil; 414 415 [self.findBarCoordinator stop]; 416 self.findBarCoordinator = nil; 417 418 [self.formInputAccessoryCoordinator stop]; 419 self.formInputAccessoryCoordinator = nil; 420 421 [self.pageInfoCoordinator stop]; 422 self.pageInfoCoordinator = nil; 423 424 [self.passKitCoordinator stop]; 425 self.passKitCoordinator = nil; 426 427 [self.passwordBreachCoordinator stop]; 428 self.passwordBreachCoordinator = nil; 429 430 self.printController = nil; 431 432 [self.qrScannerCoordinator stop]; 433 self.qrScannerCoordinator = nil; 434 435 [self.readingListCoordinator stop]; 436 self.readingListCoordinator = nil; 437 438 [self.recentTabsCoordinator stop]; 439 self.recentTabsCoordinator = nil; 440 441 [self.repostFormCoordinator stop]; 442 self.repostFormCoordinator = nil; 443 444 [self.sharingCoordinator stop]; 445 self.sharingCoordinator = nil; 446 447 [self.snackbarCoordinator stop]; 448 self.snackbarCoordinator = nil; 449 450 [self.storeKitCoordinator stop]; 451 self.storeKitCoordinator = nil; 452 453 [self.textZoomCoordinator stop]; 454 self.textZoomCoordinator = nil; 455 456 [self.translateInfobarCoordinator stop]; 457 self.translateInfobarCoordinator = nil; 458 459 [self.addCreditCardCoordinator stop]; 460 self.addCreditCardCoordinator = nil; 461 462 [self.infobarBannerOverlayContainerCoordinator stop]; 463 self.infobarBannerOverlayContainerCoordinator = nil; 464 465 [self.infobarModalOverlayContainerCoordinator stop]; 466 self.infobarModalOverlayContainerCoordinator = nil; 467 468 [self.defaultBrowserPromoCoordinator stop]; 469 self.defaultBrowserPromoCoordinator = nil; 470} 471 472#pragma mark - ActivityServiceCommands 473 474- (void)sharePage { 475 ActivityParams* params = [[ActivityParams alloc] 476 initWithScenario:ActivityScenario::TabShareButton]; 477 478 self.sharingCoordinator = [[SharingCoordinator alloc] 479 initWithBaseViewController:self.viewController 480 browser:self.browser 481 params:params 482 originView:self.viewController.activityServicePositioner 483 .sourceView 484 originRect:self.viewController.activityServicePositioner 485 .sourceRect]; 486 [self.sharingCoordinator start]; 487} 488 489- (void)shareHighlight:(ShareHighlightCommand*)command { 490 ActivityParams* params = 491 [[ActivityParams alloc] initWithURL:command.URL 492 title:command.title 493 additionalText:command.selectedText 494 scenario:ActivityScenario::SharedHighlight]; 495 496 self.sharingCoordinator = [[SharingCoordinator alloc] 497 initWithBaseViewController:self.viewController 498 browser:self.browser 499 params:params 500 originView:command.sourceView 501 originRect:command.sourceRect]; 502 [self.sharingCoordinator start]; 503} 504 505#pragma mark - BrowserCoordinatorCommands 506 507- (void)printTab { 508 DCHECK(self.printController); 509 web::WebState* webState = 510 self.browser->GetWebStateList()->GetActiveWebState(); 511 [self.printController printWebState:webState]; 512} 513 514- (void)showReadingList { 515 self.readingListCoordinator = [[ReadingListCoordinator alloc] 516 initWithBaseViewController:self.viewController 517 browser:self.browser]; 518 [self.readingListCoordinator start]; 519} 520 521- (void)showDownloadsFolder { 522 NSURL* URL = GetFilesAppUrl(); 523 if (!URL) 524 return; 525 526 [[UIApplication sharedApplication] openURL:URL 527 options:@{} 528 completionHandler:nil]; 529} 530 531- (void)showRecentTabs { 532 // TODO(crbug.com/825431): If BVC's clearPresentedState is ever called (such 533 // as in tearDown after a failed egtest), then this coordinator is left in a 534 // started state even though its corresponding VC is no longer on screen. 535 // That causes issues when the coordinator is started again and we destroy the 536 // old mediator without disconnecting it first. Temporarily work around these 537 // issues by not having a long lived coordinator. A longer-term solution will 538 // require finding a way to stop this coordinator so that the mediator is 539 // properly disconnected and destroyed and does not live longer than its 540 // associated VC. 541 if (self.recentTabsCoordinator) { 542 [self.recentTabsCoordinator stop]; 543 self.recentTabsCoordinator = nil; 544 } 545 546 self.recentTabsCoordinator = [[RecentTabsCoordinator alloc] 547 initWithBaseViewController:self.viewController 548 browser:self.browser]; 549 self.recentTabsCoordinator.loadStrategy = UrlLoadStrategy::NORMAL; 550 [self.recentTabsCoordinator start]; 551} 552 553- (void)showAddCreditCard { 554 [self.formInputAccessoryCoordinator reset]; 555 [self.addCreditCardCoordinator start]; 556} 557 558#pragma mark - WhatsNewCommands 559 560- (void)showDefaultBrowserFullscreenPromo { 561 if (!self.defaultBrowserPromoCoordinator) { 562 self.defaultBrowserPromoCoordinator = 563 [[DefaultBrowserPromoCoordinator alloc] 564 initWithBaseViewController:self.viewController 565 browser:self.browser]; 566 self.defaultBrowserPromoCoordinator.handler = self; 567 } 568 [self.defaultBrowserPromoCoordinator start]; 569} 570 571#pragma mark - DefaultBrowserPromoCommands 572 573- (void)hidePromo { 574 [self.defaultBrowserPromoCoordinator stop]; 575 self.defaultBrowserPromoCoordinator = nil; 576} 577 578#pragma mark - FindInPageCommands 579 580- (void)openFindInPage { 581 if (!self.canShowFindBar) 582 return; 583 584 self.findBarCoordinator = 585 [[FindBarCoordinator alloc] initWithBaseViewController:self.viewController 586 browser:self.browser]; 587 self.findBarCoordinator.presenter = 588 self.viewController.toolbarAccessoryPresenter; 589 self.findBarCoordinator.delegate = self; 590 self.findBarCoordinator.presentationDelegate = self.viewController; 591 592 if (self.viewController.toolbarAccessoryPresenter.isPresenting) { 593 self.nextToolbarCoordinator = self.findBarCoordinator; 594 [self closeTextZoom]; 595 return; 596 } 597 598 [self.findBarCoordinator start]; 599} 600 601- (void)closeFindInPage { 602 web::WebState* currentWebState = 603 self.browser->GetWebStateList()->GetActiveWebState(); 604 605 if (currentWebState) { 606 FindTabHelper* findTabHelper = FindTabHelper::FromWebState(currentWebState); 607 if (findTabHelper->IsFindUIActive()) { 608 findTabHelper->StopFinding(); 609 } else { 610 [self.findBarCoordinator stop]; 611 } 612 } 613} 614 615- (void)showFindUIIfActive { 616 web::WebState* currentWebState = 617 self.browser->GetWebStateList()->GetActiveWebState(); 618 auto* findHelper = FindTabHelper::FromWebState(currentWebState); 619 if (findHelper && findHelper->IsFindUIActive() && 620 !self.findBarCoordinator.presenter.isPresenting) { 621 [self.findBarCoordinator start]; 622 } 623} 624 625- (void)hideFindUI { 626 [self.findBarCoordinator stop]; 627} 628 629- (void)defocusFindInPage { 630 [self.findBarCoordinator defocusFindBar]; 631} 632 633- (void)searchFindInPage { 634 web::WebState* currentWebState = 635 self.browser->GetWebStateList()->GetActiveWebState(); 636 DCHECK(currentWebState); 637 FindTabHelper* helper = FindTabHelper::FromWebState(currentWebState); 638 helper->StartFinding([self.findBarCoordinator.findBarController searchTerm]); 639 640 if (!self.browser->GetBrowserState()->IsOffTheRecord()) 641 helper->PersistSearchTerm(); 642} 643 644- (void)findNextStringInPage { 645 web::WebState* currentWebState = 646 self.browser->GetWebStateList()->GetActiveWebState(); 647 DCHECK(currentWebState); 648 // TODO(crbug.com/603524): Reshow find bar if necessary. 649 FindTabHelper::FromWebState(currentWebState) 650 ->ContinueFinding(FindTabHelper::FORWARD); 651} 652 653- (void)findPreviousStringInPage { 654 web::WebState* currentWebState = 655 self.browser->GetWebStateList()->GetActiveWebState(); 656 DCHECK(currentWebState); 657 // TODO(crbug.com/603524): Reshow find bar if necessary. 658 FindTabHelper::FromWebState(currentWebState) 659 ->ContinueFinding(FindTabHelper::REVERSE); 660} 661 662#pragma mark - FindInPageCommands Helpers 663 664- (BOOL)canShowFindBar { 665 web::WebState* currentWebState = 666 self.browser->GetWebStateList()->GetActiveWebState(); 667 if (!currentWebState) { 668 return NO; 669 } 670 671 auto* helper = FindTabHelper::FromWebState(currentWebState); 672 return (helper && helper->CurrentPageSupportsFindInPage() && 673 !helper->IsFindUIActive()); 674} 675 676#pragma mark - PageInfoCommands 677 678- (void)legacyShowPageInfoForOriginPoint:(CGPoint)originPoint { 679 PageInfoLegacyCoordinator* pageInfoCoordinator = 680 [[PageInfoLegacyCoordinator alloc] 681 initWithBaseViewController:self.viewController 682 browser:self.browser]; 683 pageInfoCoordinator.presentationProvider = self.viewController; 684 pageInfoCoordinator.originPoint = originPoint; 685 self.pageInfoCoordinator = pageInfoCoordinator; 686 [self.pageInfoCoordinator start]; 687} 688 689- (void)showPageInfo { 690 DCHECK(base::FeatureList::IsEnabled(kPageInfoRefactoring)); 691 PageInfoCoordinator* pageInfoCoordinator = [[PageInfoCoordinator alloc] 692 initWithBaseViewController:self.viewController 693 browser:self.browser]; 694 pageInfoCoordinator.presentationProvider = self.viewController; 695 self.pageInfoCoordinator = pageInfoCoordinator; 696 [self.pageInfoCoordinator start]; 697} 698 699- (void)hidePageInfo { 700 [self.pageInfoCoordinator stop]; 701 self.pageInfoCoordinator = nil; 702} 703 704- (void)showSecurityHelpPage { 705 UrlLoadParams params = UrlLoadParams::InNewTab(GURL(kPageInfoHelpCenterURL)); 706 params.in_incognito = self.browser->GetBrowserState()->IsOffTheRecord(); 707 UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params); 708 [self hidePageInfo]; 709} 710 711#pragma mark - FormInputAccessoryCoordinatorNavigator 712 713- (void)openPasswordSettings { 714 [HandlerForProtocol(self.dispatcher, ApplicationCommands) 715 showSavedPasswordsSettingsFromViewController:self.viewController]; 716} 717 718- (void)openAddressSettings { 719 [HandlerForProtocol(self.dispatcher, ApplicationCommands) 720 showProfileSettingsFromViewController:self.viewController]; 721} 722 723- (void)openCreditCardSettings { 724 [HandlerForProtocol(self.dispatcher, ApplicationCommands) 725 showCreditCardSettingsFromViewController:self.viewController]; 726} 727 728#pragma mark - RepostFormTabHelperDelegate 729 730- (void)repostFormTabHelper:(RepostFormTabHelper*)helper 731 presentRepostFormDialogForWebState:(web::WebState*)webState 732 dialogAtPoint:(CGPoint)location 733 completionHandler:(void (^)(BOOL))completion { 734 self.repostFormCoordinator = [[RepostFormCoordinator alloc] 735 initWithBaseViewController:self.viewController 736 browser:self.browser 737 dialogLocation:location 738 webState:webState 739 completionHandler:completion]; 740 [self.repostFormCoordinator start]; 741} 742 743- (void)repostFormTabHelperDismissRepostFormDialog: 744 (RepostFormTabHelper*)helper { 745 [self.repostFormCoordinator stop]; 746 self.repostFormCoordinator = nil; 747} 748 749#pragma mark - ToolbarAccessoryCoordinatorDelegate 750 751- (void)toolbarAccessoryCoordinatorDidDismissUI: 752 (ChromeCoordinator*)coordinator { 753 if (!self.nextToolbarCoordinator) { 754 return; 755 } 756 if (self.nextToolbarCoordinator == self.findBarCoordinator) { 757 [self openFindInPage]; 758 self.nextToolbarCoordinator = nil; 759 } else if (self.nextToolbarCoordinator == self.textZoomCoordinator) { 760 [self openTextZoom]; 761 self.nextToolbarCoordinator = nil; 762 } 763} 764 765#pragma mark - TextZoomCommands 766 767- (void)openTextZoom { 768 self.textZoomCoordinator = [[TextZoomCoordinator alloc] 769 initWithBaseViewController:self.viewController 770 browser:self.browser]; 771 self.textZoomCoordinator.presenter = 772 self.viewController.toolbarAccessoryPresenter; 773 self.textZoomCoordinator.delegate = self; 774 775 if (self.viewController.toolbarAccessoryPresenter.isPresenting) { 776 self.nextToolbarCoordinator = self.textZoomCoordinator; 777 [self closeFindInPage]; 778 return; 779 } 780 781 [self.textZoomCoordinator start]; 782} 783 784- (void)closeTextZoom { 785 if (!base::FeatureList::IsEnabled(web::kWebPageTextAccessibility)) { 786 return; 787 } 788 789 web::WebState* currentWebState = 790 self.browser->GetWebStateList()->GetActiveWebState(); 791 if (currentWebState) { 792 FontSizeTabHelper* fontSizeTabHelper = 793 FontSizeTabHelper::FromWebState(currentWebState); 794 fontSizeTabHelper->SetTextZoomUIActive(false); 795 } 796 [self.textZoomCoordinator stop]; 797} 798 799- (void)showTextZoomUIIfActive { 800 web::WebState* currentWebState = 801 self.browser->GetWebStateList()->GetActiveWebState(); 802 if (!currentWebState) { 803 return; 804 } 805 806 FontSizeTabHelper* fontSizeTabHelper = 807 FontSizeTabHelper::FromWebState(currentWebState); 808 if (fontSizeTabHelper && fontSizeTabHelper->IsTextZoomUIActive() && 809 !self.textZoomCoordinator.presenter.isPresenting) { 810 [self.textZoomCoordinator start]; 811 } 812} 813 814- (void)hideTextZoomUI { 815 [self.textZoomCoordinator stop]; 816} 817 818#pragma mark - URLLoadingServiceDelegate 819 820- (void)animateOpenBackgroundTabFromParams:(const UrlLoadParams&)params 821 completion:(void (^)())completion { 822 [self.viewController 823 animateOpenBackgroundTabFromOriginPoint:params.origin_point 824 completion:completion]; 825} 826 827// TODO(crbug.com/906525) : Move WebStateListObserving out of 828// BrowserCoordinator. 829#pragma mark - WebStateListObserving 830 831- (void)webStateList:(WebStateList*)webStateList 832 didInsertWebState:(web::WebState*)webState 833 atIndex:(int)index 834 activating:(BOOL)activating { 835 [self installDelegatesForWebState:webState]; 836} 837 838- (void)webStateList:(WebStateList*)webStateList 839 didReplaceWebState:(web::WebState*)oldWebState 840 withWebState:(web::WebState*)newWebState 841 atIndex:(int)index { 842 [self uninstallDelegatesForWebState:oldWebState]; 843 [self installDelegatesForWebState:newWebState]; 844} 845 846- (void)webStateList:(WebStateList*)webStateList 847 didDetachWebState:(web::WebState*)webState 848 atIndex:(int)index { 849 [self uninstallDelegatesForWebState:webState]; 850} 851 852// TODO(crbug.com/906525) : Move out of BrowserCoordinator along with 853// WebStateListObserving. 854#pragma mark - Private WebState management methods 855 856// Adds observer for WebStateList. 857- (void)addWebStateListObserver { 858 _webStateListObserverBridge = 859 std::make_unique<WebStateListObserverBridge>(self); 860 _scopedWebStateListObserver = 861 std::make_unique<ScopedObserver<WebStateList, WebStateListObserver>>( 862 _webStateListObserverBridge.get()); 863 _scopedWebStateListObserver->Add(self.browser->GetWebStateList()); 864} 865 866// Removes observer for WebStateList. 867- (void)removeWebStateListObserver { 868 _scopedWebStateListObserver.reset(); 869 _webStateListObserverBridge.reset(); 870} 871 872// Installs delegates for each WebState in WebStateList. 873- (void)installDelegatesForAllWebStates { 874 self.openInMediator = [[OpenInMediator alloc] initWithBrowser:self.browser]; 875 876 for (int i = 0; i < self.browser->GetWebStateList()->count(); i++) { 877 web::WebState* webState = self.browser->GetWebStateList()->GetWebStateAt(i); 878 [self installDelegatesForWebState:webState]; 879 } 880} 881 882// Installs delegates for self.browser. 883- (void)installDelegatesForBrowser { 884 UrlLoadingBrowserAgent* loadingAgent = 885 UrlLoadingBrowserAgent::FromBrowser(self.browser); 886 if (loadingAgent) { 887 loadingAgent->SetDelegate(self); 888 } 889} 890 891// Uninstalls delegates for self.browser. 892- (void)uninstallDelegatesForBrowser { 893 UrlLoadingBrowserAgent* loadingAgent = 894 UrlLoadingBrowserAgent::FromBrowser(self.browser); 895 if (loadingAgent) { 896 loadingAgent->SetDelegate(nil); 897 } 898} 899 900// Uninstalls delegates for each WebState in WebStateList. 901- (void)uninstallDelegatesForAllWebStates { 902 // OpenInMediator is controlled directly monitors the webStateList and should 903 // be deleted. 904 self.openInMediator = nil; 905 for (int i = 0; i < self.browser->GetWebStateList()->count(); i++) { 906 web::WebState* webState = self.browser->GetWebStateList()->GetWebStateAt(i); 907 [self uninstallDelegatesForWebState:webState]; 908 } 909} 910 911// Install delegates for |webState|. 912- (void)installDelegatesForWebState:(web::WebState*)webState { 913 if (AutofillTabHelper::FromWebState(webState)) { 914 AutofillTabHelper::FromWebState(webState)->SetBaseViewController( 915 self.viewController); 916 } 917 918 PassKitTabHelper::CreateForWebState(webState, self.passKitCoordinator); 919 920 if (PrintTabHelper::FromWebState(webState)) { 921 PrintTabHelper::FromWebState(webState)->set_printer(self.printController); 922 } 923 924 RepostFormTabHelper::CreateForWebState(webState, self); 925 926 if (StoreKitTabHelper::FromWebState(webState)) { 927 StoreKitTabHelper::FromWebState(webState)->SetLauncher( 928 self.storeKitCoordinator); 929 } 930} 931 932// Uninstalls delegates for |webState|. 933- (void)uninstallDelegatesForWebState:(web::WebState*)webState { 934 if (PrintTabHelper::FromWebState(webState)) { 935 PrintTabHelper::FromWebState(webState)->set_printer(nil); 936 } 937 938 if (StoreKitTabHelper::FromWebState(webState)) { 939 StoreKitTabHelper::FromWebState(webState)->SetLauncher(nil); 940 } 941} 942 943#pragma mark - PasswordBreachCommands 944 945- (void)showPasswordBreachForLeakType:(CredentialLeakType)leakType 946 URL:(const GURL&)URL { 947 self.passwordBreachCoordinator = [[PasswordBreachCoordinator alloc] 948 initWithBaseViewController:self.viewController 949 browser:self.browser 950 leakType:leakType 951 URL:URL]; 952 [self.passwordBreachCoordinator start]; 953} 954 955@end 956