// Copyright 2022 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/zero_suggest_prefetch_helper.h"
#import "base/feature_list.h"
#import "components/omnibox/browser/omnibox_controller.h"
#import "ios/chrome/browser/shared/model/web_state_list/active_web_state_observation_forwarder.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer_bridge.h"
#import "ios/web/public/web_state.h"
#import "ios/web/public/web_state_observer_bridge.h"
using web::WebState;
using web::WebStateObserverBridge;
@interface ZeroSuggestPrefetchHelper () <CRWWebStateObserver,
WebStateListObserving>
@end
@implementation ZeroSuggestPrefetchHelper {
/// Bridge to receive active web state events
std::unique_ptr<ActiveWebStateObservationForwarder>
_activeWebStateObservationForwarder;
/// Bridge to receive WS events for the active web state.
std::unique_ptr<WebStateObserverBridge> _webStateObserverBridge;
/// Bridge to receive WSL events.
std::unique_ptr<WebStateListObserverBridge> _webStateListObserverBridge;
}
- (void)dealloc {
/// Reset the web state observation forwarder, which will remove
/// `_webStateObserverBridge` from the relevant observer list.
_activeWebStateObservationForwarder.reset();
if (_webStateList) {
_webStateList->RemoveObserver(_webStateListObserverBridge.get());
_webStateListObserverBridge.reset();
_webStateList = nullptr;
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (instancetype)initWithWebStateList:(WebStateList*)webStateList
controller:(OmniboxController*)controller {
self = [super init];
if (self) {
DCHECK(webStateList);
DCHECK(controller);
_webStateList = webStateList;
_controller = controller;
_webStateObserverBridge = std::make_unique<WebStateObserverBridge>(self);
_activeWebStateObservationForwarder =
std::make_unique<ActiveWebStateObservationForwarder>(
webStateList, _webStateObserverBridge.get());
_webStateListObserverBridge =
std::make_unique<WebStateListObserverBridge>(self);
_webStateList->AddObserver(_webStateListObserverBridge.get());
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateForAppWillForeground)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateForAppDidBackground)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[self startPrefetchIfNecessary];
}
return self;
}
#pragma mark - CRWWebStateObserver
- (void)webState:(web::WebState*)webState
didFinishNavigation:(web::NavigationContext*)navigationContext {
[self startPrefetchIfNecessary];
}
#pragma mark - WebStateListObserving
- (void)didChangeWebStateList:(WebStateList*)webStateList
change:(const WebStateListChange&)change
status:(const WebStateListStatus&)status {
if (status.active_web_state_change() && status.new_active_web_state) {
[self startPrefetchIfNecessary];
}
}
#pragma mark - private
/// Tell edit model to start prefetching whenever there's an active web state.
/// The prefetching is expected on navigation, tab switch, and page reload.
- (void)startPrefetchIfNecessary {
WebState* activeWebState = _webStateList->GetActiveWebState();
if (activeWebState == nullptr) {
return;
}
self.controller->StartZeroSuggestPrefetch();
}
/// Indicates to this tab helper that the app has entered a foreground state.
- (void)updateForAppWillForeground {
self.controller->autocomplete_controller()
->autocomplete_provider_client()
->set_in_background_state(false);
[self startPrefetchIfNecessary];
}
/// Indicates to this tab helper that the app has entered a background state.
- (void)updateForAppDidBackground {
self.controller->autocomplete_controller()
->autocomplete_provider_client()
->set_in_background_state(true);
}
@end