Index: chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc |
diff --git a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc |
deleted file mode 100644 |
index 47a56da7c1a0751f70dda443c7079d0fafbc5958..0000000000000000000000000000000000000000 |
--- a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc |
+++ /dev/null |
@@ -1,326 +0,0 @@ |
-// Copyright 2017 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/app_list/search_answer_web_contents_delegate.h" |
- |
-#include "base/command_line.h" |
-#include "base/metrics/histogram_macros.h" |
-#include "base/metrics/user_metrics.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/ui/browser_navigator.h" |
-#include "chrome/browser/ui/browser_navigator_params.h" |
-#include "content/public/browser/navigation_handle.h" |
-#include "content/public/browser/render_view_host.h" |
-#include "content/public/browser/web_contents.h" |
-#include "content/public/browser/web_contents_delegate.h" |
-#include "content/public/common/renderer_preferences.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/http/http_status_code.h" |
-#include "ui/app_list/app_list_features.h" |
-#include "ui/app_list/app_list_model.h" |
-#include "ui/app_list/search_box_model.h" |
-#include "ui/app_list/search_result.h" |
-#include "ui/views/controls/webview/web_contents_set_background_color.h" |
-#include "ui/views/controls/webview/webview.h" |
-#include "ui/views/widget/widget.h" |
- |
-namespace app_list { |
- |
-namespace { |
- |
-enum class SearchAnswerRequestResult { |
- REQUEST_RESULT_ANOTHER_REQUEST_STARTED = 0, |
- REQUEST_RESULT_REQUEST_FAILED = 1, |
- REQUEST_RESULT_NO_ANSWER = 2, |
- REQUEST_RESULT_RECEIVED_ANSWER = 3, |
- REQUEST_RESULT_RECEIVED_ANSWER_TOO_LARGE = 4, |
- REQUEST_RESULT_MAX = 5 |
-}; |
- |
-void RecordRequestResult(SearchAnswerRequestResult request_result) { |
- UMA_HISTOGRAM_ENUMERATION("SearchAnswer.RequestResult", request_result, |
- SearchAnswerRequestResult::REQUEST_RESULT_MAX); |
-} |
- |
-class SearchAnswerWebView : public views::WebView { |
- public: |
- explicit SearchAnswerWebView(content::BrowserContext* browser_context) |
- : WebView(browser_context) {} |
- |
- // views::WebView overrides: |
- void VisibilityChanged(View* starting_from, bool is_visible) override { |
- WebView::VisibilityChanged(starting_from, is_visible); |
- |
- if (GetWidget() && GetWidget()->IsVisible() && IsDrawn()) { |
- if (shown_time_.is_null()) |
- shown_time_ = base::TimeTicks::Now(); |
- } else { |
- if (!shown_time_.is_null()) { |
- UMA_HISTOGRAM_MEDIUM_TIMES("SearchAnswer.AnswerVisibleTime", |
- base::TimeTicks::Now() - shown_time_); |
- shown_time_ = base::TimeTicks(); |
- } |
- } |
- } |
- |
- const char* GetClassName() const override { return "SearchAnswerWebView"; } |
- |
- private: |
- // Time when the answer became visible to the user. |
- base::TimeTicks shown_time_; |
- |
- DISALLOW_COPY_AND_ASSIGN(SearchAnswerWebView); |
-}; |
- |
-class SearchAnswerResult : public SearchResult { |
- public: |
- SearchAnswerResult(Profile* profile, |
- const std::string& result_url, |
- views::View* web_view) |
- : profile_(profile) { |
- set_display_type(DISPLAY_CARD); |
- set_id(result_url); |
- set_relevance(1); |
- set_view(web_view); |
- } |
- |
- // SearchResult overrides: |
- std::unique_ptr<SearchResult> Duplicate() const override { |
- return base::MakeUnique<SearchAnswerResult>(profile_, id(), view()); |
- } |
- |
- void Open(int event_flags) override { |
- chrome::NavigateParams params(profile_, GURL(id()), |
- ui::PAGE_TRANSITION_GENERATED); |
- params.disposition = ui::DispositionFromEventFlags(event_flags); |
- chrome::Navigate(¶ms); |
- } |
- |
- private: |
- Profile* const profile_; |
-}; |
- |
-} // namespace |
- |
-SearchAnswerWebContentsDelegate::SearchAnswerWebContentsDelegate( |
- Profile* profile, |
- app_list::AppListModel* model) |
- : profile_(profile), |
- model_(model), |
- web_view_(base::MakeUnique<SearchAnswerWebView>(profile)), |
- web_contents_( |
- content::WebContents::Create(content::WebContents::CreateParams( |
- profile, |
- content::SiteInstance::Create(profile)))), |
- answer_server_url_(features::AnswerServerUrl()) { |
- content::RendererPreferences* renderer_prefs = |
- web_contents_->GetMutableRendererPrefs(); |
- renderer_prefs->can_accept_load_drops = false; |
- // We need the OpenURLFromTab() to get called. |
- renderer_prefs->browser_handles_all_top_level_requests = true; |
- web_contents_->GetRenderViewHost()->SyncRendererPrefs(); |
- |
- Observe(web_contents_.get()); |
- web_contents_->SetDelegate(this); |
- web_view_->set_owned_by_client(); |
- web_view_->SetWebContents(web_contents_.get()); |
- |
- // Make the webview transparent since it's going to be shown on top of a |
- // highlightable button. |
- views::WebContentsSetBackgroundColor::CreateForWebContentsWithColor( |
- web_contents_.get(), SK_ColorTRANSPARENT); |
-} |
- |
-SearchAnswerWebContentsDelegate::~SearchAnswerWebContentsDelegate() { |
- RecordReceivedAnswerFinalResult(); |
-} |
- |
-views::View* SearchAnswerWebContentsDelegate::web_view() { |
- return web_view_.get(); |
-} |
- |
-void SearchAnswerWebContentsDelegate::Start(bool is_voice_query, |
- const base::string16& query) { |
- RecordReceivedAnswerFinalResult(); |
- // Reset the state. |
- received_answer_ = false; |
- OnResultAvailable(false); |
- current_request_url_ = GURL(); |
- server_request_start_time_ = answer_loaded_time_ = base::TimeTicks(); |
- |
- if (is_voice_query) { |
- // No need to send a server request and show a card because launcher |
- // automatically closes upon voice queries. |
- return; |
- } |
- |
- if (!model_->search_engine_is_google()) |
- return; |
- |
- if (query.empty()) |
- return; |
- |
- // Start a request to the answer server. |
- |
- // Lifetime of |prefixed_query| should be longer than the one of |
- // |replacements|. |
- base::string16 prefixed_query(base::UTF8ToUTF16("q=") + query); |
- GURL::ReplacementsW replacements; |
- replacements.SetQueryStr(prefixed_query); |
- current_request_url_ = answer_server_url_.ReplaceComponents(replacements); |
- |
- content::NavigationController::LoadURLParams load_params( |
- current_request_url_); |
- load_params.transition_type = ui::PAGE_TRANSITION_AUTO_TOPLEVEL; |
- load_params.should_clear_history_list = true; |
- web_contents_->GetController().LoadURLWithParams(load_params); |
- server_request_start_time_ = base::TimeTicks::Now(); |
- |
- // We are going to call WebContents::GetPreferredSize(). |
- web_contents_->GetRenderViewHost()->EnablePreferredSizeMode(); |
-} |
- |
-void SearchAnswerWebContentsDelegate::UpdatePreferredSize( |
- content::WebContents* web_contents, |
- const gfx::Size& pref_size) { |
- OnResultAvailable(received_answer_ && IsCardSizeOk() && |
- !web_contents_->IsLoading()); |
- web_view_->SetPreferredSize(pref_size); |
- if (!answer_loaded_time_.is_null()) { |
- UMA_HISTOGRAM_TIMES("SearchAnswer.ResizeAfterLoadTime", |
- base::TimeTicks::Now() - answer_loaded_time_); |
- } |
-} |
- |
-content::WebContents* SearchAnswerWebContentsDelegate::OpenURLFromTab( |
- content::WebContents* source, |
- const content::OpenURLParams& params) { |
- if (!params.user_gesture) |
- return WebContentsDelegate::OpenURLFromTab(source, params); |
- |
- // Open the user-clicked link in the browser taking into account the requested |
- // disposition. |
- chrome::NavigateParams new_tab_params(profile_, params.url, |
- params.transition); |
- |
- new_tab_params.disposition = params.disposition; |
- |
- if (params.disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB) { |
- // When the user asks to open a link as a background tab, we show an |
- // activated window with the new activated tab after the user closes the |
- // launcher. So it's "background" relative to the launcher itself. |
- new_tab_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; |
- new_tab_params.window_action = chrome::NavigateParams::SHOW_WINDOW_INACTIVE; |
- } |
- |
- chrome::Navigate(&new_tab_params); |
- |
- base::RecordAction(base::UserMetricsAction("SearchAnswer_OpenedUrl")); |
- |
- return new_tab_params.target_contents; |
-} |
- |
-bool SearchAnswerWebContentsDelegate::HandleContextMenu( |
- const content::ContextMenuParams& params) { |
- // Disable showing the menu. |
- return true; |
-} |
- |
-void SearchAnswerWebContentsDelegate::DidFinishNavigation( |
- content::NavigationHandle* navigation_handle) { |
- if (navigation_handle->GetURL() != current_request_url_) { |
- RecordRequestResult( |
- SearchAnswerRequestResult::REQUEST_RESULT_ANOTHER_REQUEST_STARTED); |
- return; |
- } |
- |
- if (!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage() || |
- !navigation_handle->IsInMainFrame()) { |
- RecordRequestResult( |
- SearchAnswerRequestResult::REQUEST_RESULT_REQUEST_FAILED); |
- return; |
- } |
- |
- if (!features::IsAnswerCardDarkRunEnabled()) { |
- if (!ParseResponseHeaders(navigation_handle->GetResponseHeaders())) { |
- RecordRequestResult(SearchAnswerRequestResult::REQUEST_RESULT_NO_ANSWER); |
- return; |
- } |
- } else { |
- // In the dark run mode, every other "server response" contains a card. |
- dark_run_received_answer_ = !dark_run_received_answer_; |
- if (!dark_run_received_answer_) |
- return; |
- // SearchResult requires a non-empty id. This "url" will never be opened. |
- result_url_ = "some string"; |
- } |
- |
- received_answer_ = true; |
- UMA_HISTOGRAM_TIMES("SearchAnswer.NavigationTime", |
- base::TimeTicks::Now() - server_request_start_time_); |
-} |
- |
-void SearchAnswerWebContentsDelegate::DidStopLoading() { |
- if (!received_answer_) |
- return; |
- |
- if (IsCardSizeOk()) |
- OnResultAvailable(true); |
- answer_loaded_time_ = base::TimeTicks::Now(); |
- UMA_HISTOGRAM_TIMES("SearchAnswer.LoadingTime", |
- answer_loaded_time_ - server_request_start_time_); |
- base::RecordAction(base::UserMetricsAction("SearchAnswer_StoppedLoading")); |
-} |
- |
-void SearchAnswerWebContentsDelegate::DidGetUserInteraction( |
- const blink::WebInputEvent::Type type) { |
- base::RecordAction(base::UserMetricsAction("SearchAnswer_UserInteraction")); |
-} |
- |
-bool SearchAnswerWebContentsDelegate::IsCardSizeOk() const { |
- if (features::IsAnswerCardDarkRunEnabled()) |
- return true; |
- |
- const gfx::Size size = web_contents_->GetPreferredSize(); |
- return size.width() <= features::AnswerCardMaxWidth() && |
- size.height() <= features::AnswerCardMaxHeight(); |
-} |
- |
-void SearchAnswerWebContentsDelegate::RecordReceivedAnswerFinalResult() { |
- // Recording whether a server response with an answer contains a card of a |
- // fitting size, or a too large one. Cannot do this in DidStopLoading() or |
- // UpdatePreferredSize() because this may be followed by a resizing with |
- // different dimensions, so this method gets called when card's life ends. |
- if (!received_answer_) |
- return; |
- |
- RecordRequestResult( |
- IsCardSizeOk() ? SearchAnswerRequestResult::REQUEST_RESULT_RECEIVED_ANSWER |
- : SearchAnswerRequestResult:: |
- REQUEST_RESULT_RECEIVED_ANSWER_TOO_LARGE); |
-} |
- |
-void SearchAnswerWebContentsDelegate::OnResultAvailable(bool is_available) { |
- SearchProvider::Results results; |
- if (is_available) { |
- results.reserve(1); |
- results.emplace_back(base::MakeUnique<SearchAnswerResult>( |
- profile_, result_url_, web_view_.get())); |
- } |
- SwapResults(&results); |
-} |
- |
-bool SearchAnswerWebContentsDelegate::ParseResponseHeaders( |
- const net::HttpResponseHeaders* headers) { |
- if (!headers || headers->response_code() != net::HTTP_OK) |
- return false; |
- if (!headers->HasHeaderValue("SearchAnswer-HasResult", "true")) |
- return false; |
- if (!headers->GetNormalizedHeader("SearchAnswer-OpenResultUrl", &result_url_)) |
- return false; |
- return true; |
-} |
- |
-} // namespace app_list |