chromium/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm

// Copyright 2017 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/omnibox/popup/omnibox_popup_coordinator.h"

#import "base/feature_list.h"
#import "components/favicon/core/large_icon_service.h"
#import "components/feature_engagement/public/tracker.h"
#import "components/history/core/browser/top_sites.h"
#import "components/image_fetcher/core/image_data_fetcher.h"
#import "components/omnibox/browser/autocomplete_result.h"
#import "components/omnibox/common/omnibox_features.h"
#import "components/search_engines/template_url_service.h"
#import "ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_large_icon_cache_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_large_icon_service_factory.h"
#import "ios/chrome/browser/favicon/ui_bundled/favicon_attributes_provider.h"
#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
#import "ios/chrome/browser/history/model/top_sites_factory.h"
#import "ios/chrome/browser/net/model/crurl.h"
#import "ios/chrome/browser/policy/model/policy_util.h"
#import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
#import "ios/chrome/browser/shared/coordinator/layout_guide/layout_guide_util.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/shared/public/commands/application_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/omnibox_commands.h"
#import "ios/chrome/browser/shared/public/commands/quick_delete_commands.h"
#import "ios/chrome/browser/shared/public/commands/settings_commands.h"
#import "ios/chrome/browser/shared/public/commands/snackbar_commands.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/shared/public/features/system_flags.h"
#import "ios/chrome/browser/ui/menu/browser_action_factory.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_ui_features.h"
#import "ios/chrome/browser/ui/omnibox/popup/carousel/carousel_item.h"
#import "ios/chrome/browser/ui/omnibox/popup/carousel/carousel_item_menu_provider.h"
#import "ios/chrome/browser/ui/omnibox/popup/content_providing.h"
#import "ios/chrome/browser/ui/omnibox/popup/omnibox_pedal_annotator.h"
#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h"
#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_presenter.h"
#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h"
#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h"
#import "ios/chrome/browser/ui/omnibox/popup/pedal_section_extractor.h"
#import "ios/chrome/browser/ui/omnibox/popup/popup_debug_info_view_controller.h"
#import "ios/chrome/browser/ui/sharing/sharing_coordinator.h"
#import "ios/chrome/browser/ui/sharing/sharing_params.h"
#import "services/network/public/cpp/shared_url_loader_factory.h"
#import "ui/base/device_form_factor.h"

@interface OmniboxPopupCoordinator () <OmniboxPopupMediatorProtocolProvider,
                                       OmniboxPopupMediatorSharingDelegate> {
  std::unique_ptr<OmniboxPopupViewIOS> _popupView;
}

@property(nonatomic, strong) OmniboxPopupViewController* popupViewController;
@property(nonatomic, strong) OmniboxPopupMediator* mediator;
@property(nonatomic, strong) SharingCoordinator* sharingCoordinator;

// Owned by OmniboxEditModel.
@property(nonatomic, assign) AutocompleteController* autocompleteController;

@end

@implementation OmniboxPopupCoordinator

#pragma mark - Public

- (instancetype)
    initWithBaseViewController:(UIViewController*)viewController
                       browser:(Browser*)browser
        autocompleteController:(AutocompleteController*)autocompleteController
                     popupView:(std::unique_ptr<OmniboxPopupViewIOS>)popupView {
  self = [super initWithBaseViewController:nil browser:browser];
  if (self) {
    DCHECK(autocompleteController);
    _autocompleteController = autocompleteController;
    _popupView = std::move(popupView);
    _popupViewController = [[OmniboxPopupViewController alloc] init];
    _popupReturnDelegate = _popupViewController;
    _KeyboardDelegate = _popupViewController;
  }
  return self;
}

- (void)start {
  std::unique_ptr<image_fetcher::ImageDataFetcher> imageFetcher =
      std::make_unique<image_fetcher::ImageDataFetcher>(
          self.browser->GetBrowserState()->GetSharedURLLoaderFactory());

  BOOL isIncognito = self.browser->GetBrowserState()->IsOffTheRecord();

  RemoteSuggestionsService* remoteSuggestionsService =
      RemoteSuggestionsServiceFactory::GetForBrowserState(
          self.browser->GetBrowserState(), /*create_if_necessary=*/true);

  self.mediator = [[OmniboxPopupMediator alloc]
               initWithFetcher:std::move(imageFetcher)
                 faviconLoader:IOSChromeFaviconLoaderFactory::
                                   GetForBrowserState(
                                       self.browser->GetBrowserState())
        autocompleteController:self.autocompleteController
      remoteSuggestionsService:remoteSuggestionsService
                      delegate:_popupView.get()
                       tracker:feature_engagement::TrackerFactory::
                                   GetForBrowserState(
                                       self.browser->GetBrowserState())];

  TemplateURLService* templateURLService =
      ios::TemplateURLServiceFactory::GetForBrowserState(
          self.browser->GetBrowserState());
  self.mediator.defaultSearchEngineIsGoogle =
      templateURLService && templateURLService->GetDefaultSearchProvider() &&
      templateURLService->GetDefaultSearchProvider()->GetEngineType(
          templateURLService->search_terms_data()) == SEARCH_ENGINE_GOOGLE;
  self.mediator.protocolProvider = self;
  self.mediator.sharingDelegate = self;
  BrowserActionFactory* actionFactory = [[BrowserActionFactory alloc]
      initWithBrowser:self.browser
             scenario:kMenuScenarioHistogramOmniboxMostVisitedEntry];
  self.mediator.mostVisitedActionFactory = actionFactory;
  self.popupViewController.imageRetriever = self.mediator;
  self.popupViewController.faviconRetriever = self.mediator;
  self.popupViewController.delegate = self.mediator;
  self.popupViewController.dataSource = self.mediator;
  self.popupViewController.incognito = isIncognito;
  favicon::LargeIconService* largeIconService =
      IOSChromeLargeIconServiceFactory::GetForBrowserState(
          self.browser->GetBrowserState());
  LargeIconCache* cache = IOSChromeLargeIconCacheFactory::GetForBrowserState(
      self.browser->GetBrowserState());
  self.popupViewController.largeIconService = largeIconService;
  self.popupViewController.largeIconCache = cache;
  self.popupViewController.carouselMenuProvider = self.mediator;
  self.popupViewController.layoutGuideCenter =
      LayoutGuideCenterForBrowser(self.browser);

  self.mediator.consumer = self.popupViewController;
  self.popupViewController.matchPreviewDelegate =
      self.popupMatchPreviewDelegate;
  self.popupViewController.acceptReturnDelegate = self.acceptReturnDelegate;
  self.mediator.carouselItemConsumer = self.popupViewController;
  self.mediator.allowIncognitoActions =
      !IsIncognitoModeDisabled(self.browser->GetBrowserState()->GetPrefs());

  CommandDispatcher* dispatcher = self.browser->GetCommandDispatcher();
  OmniboxPedalAnnotator* annotator = [[OmniboxPedalAnnotator alloc] init];
  annotator.applicationHandler =
      HandlerForProtocol(dispatcher, ApplicationCommands);
  annotator.settingsHandler = HandlerForProtocol(dispatcher, SettingsCommands);
  annotator.omniboxHandler = HandlerForProtocol(dispatcher, OmniboxCommands);
  annotator.quickDeleteHandler =
      HandlerForProtocol(dispatcher, QuickDeleteCommands);

  self.mediator.pedalAnnotator = annotator;

  self.mediator.applicationCommandsHandler =
      HandlerForProtocol(dispatcher, ApplicationCommands);
  self.mediator.incognito = isIncognito;
  self.mediator.sceneState = self.browser->GetSceneState();
  self.mediator.presenter = [[OmniboxPopupPresenter alloc]
      initWithPopupPresenterDelegate:self.presenterDelegate
                 popupViewController:self.popupViewController
                   layoutGuideCenter:LayoutGuideCenterForBrowser(self.browser)
                           incognito:isIncognito];

  _popupView->SetMediator(self.mediator);

  if (experimental_flags::IsOmniboxDebuggingEnabled()) {
    [self setupDebug];
  }
}

- (void)stop {
  [self.mediator disconnect];

  [self.sharingCoordinator stop];
  self.sharingCoordinator = nil;
  _popupView.reset();
}

- (BOOL)isOpen {
  return self.mediator.isOpen;
}

- (id<ToolbarOmniboxConsumer>)toolbarOmniboxConsumer {
  return self.mediator.presenter;
}

- (void)toggleOmniboxDebuggerView {
  CHECK(experimental_flags::IsOmniboxDebuggingEnabled());
  [self.popupViewController toggleOmniboxDebuggerView];
}

#pragma mark - Property accessor

- (BOOL)hasResults {
  return self.mediator.hasResults;
}

#pragma mark - OmniboxPopupMediatorProtocolProvider

- (scoped_refptr<history::TopSites>)topSites {
  return ios::TopSitesFactory::GetForBrowserState(
      self.browser->GetBrowserState());
}

- (id<SnackbarCommands>)snackbarCommandsHandler {
  return HandlerForProtocol(self.browser->GetCommandDispatcher(),
                            SnackbarCommands);
}

#pragma mark - OmniboxPopupMediatorSharingDelegate

/// Triggers the URL sharing flow for the given `URL` and `title`, with the
/// origin `view` representing the UI component for that URL.
- (void)popupMediator:(OmniboxPopupMediator*)mediator
             shareURL:(GURL)URL
                title:(NSString*)title
           originView:(UIView*)originView {
  SharingParams* params = [[SharingParams alloc]
      initWithURL:URL
            title:title
         scenario:SharingScenario::OmniboxMostVisitedEntry];
  self.sharingCoordinator = [[SharingCoordinator alloc]
      initWithBaseViewController:self.popupViewController
                         browser:self.browser
                          params:params
                      originView:originView];
  [self.sharingCoordinator start];
}

#pragma mark - private

- (void)setupDebug {
  DCHECK(experimental_flags::IsOmniboxDebuggingEnabled());

  PopupDebugInfoViewController* viewController =
      [[PopupDebugInfoViewController alloc] init];
  self.mediator.debugInfoConsumer = viewController;

  UINavigationController* navController = [[UINavigationController alloc]
      initWithRootViewController:viewController];
  self.popupViewController.debugInfoViewController = navController;
}

@end