| // Copyright 2019 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. |
| |
| #include "chrome/browser/ui/ash/assistant/proactive_suggestions_client_impl.h" |
| |
| #include "ash/public/cpp/assistant/proactive_suggestions.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/ash/assistant/assistant_client.h" |
| #include "chrome/browser/ui/ash/assistant/proactive_suggestions_loader.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| |
| ProactiveSuggestionsClientImpl::ProactiveSuggestionsClientImpl( |
| AssistantClient* client, |
| Profile* profile) |
| : profile_(profile) { |
| // Initialize the Assistant state proxy. |
| mojo::PendingRemote<ash::mojom::VoiceInteractionController> controller; |
| client->RequestVoiceInteractionController( |
| controller.InitWithNewPipeAndPassReceiver()); |
| assistant_state_.Init(std::move(controller)); |
| |
| // We observe Assistant state to detect enabling/disabling of Assistant in |
| // settings as well as enabling/disabling of screen context. |
| assistant_state_.AddObserver(this); |
| |
| // We observe the singleton BrowserList to receive events pertaining to the |
| // currently active browser. |
| BrowserList::AddObserver(this); |
| } |
| |
| ProactiveSuggestionsClientImpl::~ProactiveSuggestionsClientImpl() { |
| if (delegate_) |
| delegate_->OnProactiveSuggestionsClientDestroying(); |
| |
| WebContentsObserver::Observe(nullptr); |
| |
| if (active_browser_) |
| active_browser_->tab_strip_model()->RemoveObserver(this); |
| |
| BrowserList::RemoveObserver(this); |
| assistant_state_.RemoveObserver(this); |
| } |
| |
| void ProactiveSuggestionsClientImpl::SetDelegate(Delegate* delegate) { |
| if (delegate == delegate_) |
| return; |
| |
| delegate_ = delegate; |
| |
| // When a |delegate_| is set, we need to notify it of the active set of |
| // proactive suggestions, if such a set exists. Failure to do so will leave |
| // the |delegate_| without an update until the active browser context changes. |
| if (delegate_ && active_proactive_suggestions_) |
| delegate_->OnProactiveSuggestionsChanged(active_proactive_suggestions_); |
| } |
| |
| void ProactiveSuggestionsClientImpl::OnBrowserRemoved(Browser* browser) { |
| if (browser == active_browser_) |
| SetActiveBrowser(nullptr); |
| } |
| |
| void ProactiveSuggestionsClientImpl::OnBrowserSetLastActive(Browser* browser) { |
| SetActiveBrowser(browser); |
| } |
| |
| void ProactiveSuggestionsClientImpl::OnBrowserNoLongerActive(Browser* browser) { |
| if (browser == active_browser_) |
| SetActiveBrowser(nullptr); |
| } |
| |
| void ProactiveSuggestionsClientImpl::OnTabStripModelChanged( |
| TabStripModel* tab_strip_model, |
| const TabStripModelChange& change, |
| const TabStripSelectionChange& selection) { |
| // When the currently active browser tab changes, that indicates there has |
| // been a change in the active contents. |
| if (selection.active_tab_changed()) |
| SetActiveContents(tab_strip_model->GetActiveWebContents()); |
| } |
| |
| void ProactiveSuggestionsClientImpl::DidStartNavigation( |
| content::NavigationHandle* navigation_handle) { |
| SetActiveUrl(active_contents_->GetURL()); |
| } |
| |
| void ProactiveSuggestionsClientImpl::OnVoiceInteractionSettingsEnabled( |
| bool enabled) { |
| // When Assistant is enabled/disabled in settings we may need to resume/pause |
| // observation of the browser. We accomplish this by updating active state. |
| UpdateActiveState(); |
| } |
| |
| void ProactiveSuggestionsClientImpl::OnVoiceInteractionContextEnabled( |
| bool enabled) { |
| // When Assistant screen context is enabled/disabled in settings we may need |
| // to resume/pause observation of the browser. We accomplish this by updating |
| // active state. |
| UpdateActiveState(); |
| } |
| |
| void ProactiveSuggestionsClientImpl::SetActiveBrowser(Browser* browser) { |
| if (browser == active_browser_) |
| return; |
| |
| // Clean up bindings on the previously active browser. |
| if (active_browser_) |
| active_browser_->tab_strip_model()->RemoveObserver(this); |
| |
| active_browser_ = browser; |
| |
| // We need to update active state to conditionally observe the active browser. |
| UpdateActiveState(); |
| } |
| |
| void ProactiveSuggestionsClientImpl::SetActiveContents( |
| content::WebContents* contents) { |
| if (contents == active_contents_) |
| return; |
| |
| active_contents_ = contents; |
| |
| // We observe the active contents so as to detect navigation changes. |
| WebContentsObserver::Observe(active_contents_); |
| |
| // Perform an initial sync of the active url. |
| SetActiveUrl(active_contents_ ? active_contents_->GetURL() : GURL()); |
| } |
| |
| void ProactiveSuggestionsClientImpl::SetActiveUrl(const GURL& url) { |
| if (url == active_url_) |
| return; |
| |
| active_url_ = url; |
| |
| // The previous set of proactive suggestions is no longer valid. |
| SetActiveProactiveSuggestions(nullptr); |
| |
| if (active_url_.is_empty()) { |
| loader_.reset(); |
| return; |
| } |
| |
| // Start loading new proactive suggestions associated with the active url. |
| loader_ = std::make_unique<ProactiveSuggestionsLoader>(profile_, active_url_); |
| loader_->Start(base::BindOnce( |
| &ProactiveSuggestionsClientImpl::SetActiveProactiveSuggestions, |
| base::Unretained(this))); |
| } |
| |
| void ProactiveSuggestionsClientImpl::SetActiveProactiveSuggestions( |
| scoped_refptr<ash::ProactiveSuggestions> proactive_suggestions) { |
| if (ash::ProactiveSuggestions::AreEqual( |
| proactive_suggestions.get(), active_proactive_suggestions_.get())) { |
| return; |
| } |
| |
| active_proactive_suggestions_ = std::move(proactive_suggestions); |
| |
| if (delegate_) |
| delegate_->OnProactiveSuggestionsChanged(active_proactive_suggestions_); |
| } |
| |
| void ProactiveSuggestionsClientImpl::UpdateActiveState() { |
| if (!active_browser_) { |
| SetActiveContents(nullptr); |
| return; |
| } |
| |
| auto* tab_strip_model = active_browser_->tab_strip_model(); |
| |
| // We never observe browsers that are off the record and we never observe |
| // browsers when the user has disabled either Assistant or screen context. |
| if (active_browser_->profile()->IsOffTheRecord() || |
| !assistant_state_.settings_enabled().value_or(false) || |
| !assistant_state_.context_enabled().value_or(false)) { |
| tab_strip_model->RemoveObserver(this); |
| SetActiveContents(nullptr); |
| return; |
| } |
| |
| // We observe the tab strip associated with the active browser so as to detect |
| // changes to the currently active tab. |
| tab_strip_model->AddObserver(this); |
| |
| // Perform an initial sync of the active contents. |
| SetActiveContents(tab_strip_model->GetActiveWebContents()); |
| } |