Commit 6f339856 authored by Xiyuan Xia's avatar Xiyuan Xia Committed by Commit Bot

app_list: Answer card in mash

- AnswerCardWebContents uses RemoteViewProvider to prepare answer card
  contents for embedding;
- SearchResultAnswerCardView uses RemoteViewHost to embed the
  contents from AnserCardWebContents;

Bug: 812434
Change-Id: I2c9785c96987367a72278c66205f20e579bf91ca
Reviewed-on: https://chromium-review.googlesource.com/992361
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548835}
parent 361abda7
......@@ -3573,6 +3573,7 @@ split_static_library("ui") {
deps += [
"//ui/app_list",
"//ui/app_list/vector_icons",
"//ui/views/mus/remote_view:remote_view_provider",
]
if (is_chromeos) {
......
......@@ -36,7 +36,9 @@ class AnswerCardContents {
bool has_answer_card,
const std::string& result_title,
const std::string& issued_query) = 0;
virtual void DidStopLoading(const AnswerCardContents* source) = 0;
// Invoked when |source| is ready to be shown.
virtual void OnContentsReady(const AnswerCardContents* source) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Delegate);
......
......@@ -162,7 +162,7 @@ void AnswerCardSearchProvider::DidFinishNavigation(
base::TimeTicks::Now() - server_request_start_time_);
}
void AnswerCardSearchProvider::DidStopLoading(
void AnswerCardSearchProvider::OnContentsReady(
const AnswerCardContents* source) {
NavigationContext& context_for_loading = GetNavigationContextForLoading();
DCHECK_EQ(source, context_for_loading.contents.get());
......
......@@ -43,7 +43,7 @@ class AnswerCardSearchProvider : public SearchProvider,
bool has_answer_card,
const std::string& result_title,
const std::string& issued_query) override;
void DidStopLoading(const AnswerCardContents* source) override;
void OnContentsReady(const AnswerCardContents* source) override;
private:
enum class RequestState {
......
......@@ -94,7 +94,7 @@ class AnswerCardSearchProviderTest : public AppListTestBase {
has_error, has_answer_card, title,
issued_query);
provider()->DidStopLoading(contents);
provider()->OnContentsReady(contents);
EXPECT_EQ(expected_result_count, results().size());
......@@ -191,7 +191,7 @@ TEST_F(AnswerCardSearchProviderTest, Basic) {
provider()->Start(base::UTF8ToUTF16(kCatQuery));
provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
VerifyResult("Basic Result", kCatCardId, token1(), kCatCardTitle);
......@@ -215,7 +215,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueries) {
provider()->Start(base::UTF8ToUTF16(kCatQuery));
provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
......@@ -232,7 +232,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueries) {
// The cat still stays.
VerifyResult("Cat Result 3", kCatCardId, token1(), kCatCardTitle);
provider()->DidStopLoading(contents0());
provider()->OnContentsReady(contents0());
// Once the dog finishes loading, it replaces the cat.
VerifyResult("Dog Result 1", kDogCardId, token0(), kDogCardTitle);
......@@ -249,7 +249,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueries) {
VerifyResult("Dog Result 3", kDogCardId, token0(), kDogCardTitle);
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
VerifyResult("Shark Result", kSharkCardId, token1(), kSharkCardTitle);
}
......@@ -261,7 +261,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondErrors) {
provider()->Start(base::UTF8ToUTF16(kCatQuery));
provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
......@@ -276,7 +276,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondErrors) {
EXPECT_EQ(0UL, results().size());
provider()->DidStopLoading(contents0());
provider()->OnContentsReady(contents0());
EXPECT_EQ(0UL, results().size());
......@@ -291,7 +291,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondErrors) {
EXPECT_EQ(0UL, results().size());
provider()->DidStopLoading(contents0());
provider()->OnContentsReady(contents0());
VerifyResult("Shark Result", kSharkCardId, token0(), kSharkCardTitle);
}
......@@ -304,7 +304,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondNoCard) {
provider()->Start(base::UTF8ToUTF16(kCatQuery));
provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
......@@ -319,7 +319,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondNoCard) {
EXPECT_EQ(0UL, results().size());
provider()->DidStopLoading(contents0());
provider()->OnContentsReady(contents0());
EXPECT_EQ(0UL, results().size());
......@@ -334,7 +334,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondNoCard) {
EXPECT_EQ(0UL, results().size());
provider()->DidStopLoading(contents0());
provider()->OnContentsReady(contents0());
VerifyResult("Shark Result", kSharkCardId, token0(), kSharkCardTitle);
}
......@@ -357,17 +357,17 @@ TEST_F(AnswerCardSearchProviderTest, InterruptedRequest) {
provider()->DidFinishNavigation(contents1(), GetSearchUrl("c"), false, true,
"Title c", "c");
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
EXPECT_EQ(0UL, results().size());
provider()->DidFinishNavigation(contents1(), GetSearchUrl("ca"), false, true,
"Title ca", "ca");
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
EXPECT_EQ(0UL, results().size());
provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
VerifyResult("Cat Result", kCatCardId, token1(), kCatCardTitle);
}
......@@ -379,7 +379,7 @@ TEST_F(AnswerCardSearchProviderTest, InterruptedRequestAfterResult) {
provider()->Start(base::UTF8ToUTF16(kCatQuery));
provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
provider()->OnContentsReady(contents1());
VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
......@@ -400,19 +400,19 @@ TEST_F(AnswerCardSearchProviderTest, InterruptedRequestAfterResult) {
provider()->DidFinishNavigation(contents0(), GetSearchUrl("d"), false, true,
"Title d", "d");
provider()->DidStopLoading(contents0());
provider()->OnContentsReady(contents0());
VerifyResult("Cat Result 5", kCatCardId, token1(), kCatCardTitle);
provider()->DidFinishNavigation(contents0(), GetSearchUrl("do"), false, true,
"Title do", "do");
provider()->DidStopLoading(contents0());
provider()->OnContentsReady(contents0());
VerifyResult("Cat Result 5", kCatCardId, token1(), kCatCardTitle);
provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), false,
true, kDogCardTitle, kDogQuery);
provider()->DidStopLoading(contents0());
provider()->OnContentsReady(contents0());
VerifyResult("Dog Result", kDogCardId, token0(), kDogCardTitle);
}
......
......@@ -6,6 +6,7 @@
#include <string>
#include "base/bind.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "chrome/browser/profiles/profile.h"
......@@ -27,6 +28,7 @@
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/controls/webview/web_contents_set_background_color.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/mus/remote_view/remote_view_provider.h"
#include "ui/views/widget/widget.h"
namespace app_list {
......@@ -135,12 +137,12 @@ void ParseResponseHeaders(const net::HttpResponseHeaders* headers,
} // namespace
AnswerCardWebContents::AnswerCardWebContents(Profile* profile)
: web_view_(std::make_unique<SearchAnswerWebView>(profile)),
web_contents_(
: web_contents_(
content::WebContents::Create(content::WebContents::CreateParams(
profile,
content::SiteInstance::Create(profile)))),
profile_(profile) {
profile_(profile),
weak_ptr_factory_(this) {
content::RendererPreferences* renderer_prefs =
web_contents_->GetMutableRendererPrefs();
renderer_prefs->can_accept_load_drops = false;
......@@ -150,9 +152,6 @@ AnswerCardWebContents::AnswerCardWebContents(Profile* profile)
Observe(web_contents_.get());
web_contents_->SetDelegate(this);
web_view_->set_owned_by_client();
web_view_->SetWebContents(web_contents_.get());
web_view_->SetResizeBackgroundColor(SK_ColorTRANSPARENT);
// Make the webview transparent since it's going to be shown on top of a
// highlightable button.
......@@ -163,8 +162,17 @@ AnswerCardWebContents::AnswerCardWebContents(Profile* profile)
if (rvh)
AttachToHost(rvh->GetWidget());
if (AnswerCardContentsRegistry::Get())
if (AnswerCardContentsRegistry::Get()) {
web_view_ = std::make_unique<SearchAnswerWebView>(profile);
web_view_->set_owned_by_client();
web_view_->SetWebContents(web_contents_.get());
web_view_->SetResizeBackgroundColor(SK_ColorTRANSPARENT);
token_ = AnswerCardContentsRegistry::Get()->Register(web_view_.get());
} else {
remote_view_provider_ = std::make_unique<views::RemoteViewProvider>(
web_contents_->GetNativeView());
}
}
AnswerCardWebContents::~AnswerCardWebContents() {
......@@ -194,7 +202,10 @@ void AnswerCardWebContents::ResizeDueToAutoResize(
content::WebContents* web_contents,
const gfx::Size& new_size) {
delegate()->UpdatePreferredSize(this);
web_view_->SetPreferredSize(new_size);
if (web_view_)
web_view_->SetPreferredSize(new_size);
// TODO(https://crbug.com/812434): Support preferred size change for mash.
}
content::WebContents* AnswerCardWebContents::OpenURLFromTab(
......@@ -254,7 +265,14 @@ void AnswerCardWebContents::DidFinishNavigation(
}
void AnswerCardWebContents::DidStopLoading() {
delegate()->DidStopLoading(this);
if (!remote_view_provider_) {
delegate()->OnContentsReady(this);
return;
}
remote_view_provider_->GetEmbedToken(
base::BindOnce(&AnswerCardWebContents::OnGotEmbedTokenAndNotify,
weak_ptr_factory_.GetWeakPtr()));
}
void AnswerCardWebContents::DidGetUserInteraction(
......@@ -298,4 +316,11 @@ void AnswerCardWebContents::DetachFromHost() {
host_ = nullptr;
}
void AnswerCardWebContents::OnGotEmbedTokenAndNotify(
const base::UnguessableToken& token) {
token_ = token;
web_contents_->GetNativeView()->Show();
delegate()->OnContentsReady(this);
}
} // namespace app_list
......@@ -7,6 +7,7 @@
#include <memory>
#include "base/memory/weak_ptr.h"
#include "base/unguessable_token.h"
#include "chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h"
#include "content/public/browser/render_widget_host.h"
......@@ -16,6 +17,7 @@
class Profile;
namespace views {
class RemoteViewProvider;
class WebView;
}
......@@ -55,19 +57,31 @@ class AnswerCardWebContents : public AnswerCardContents,
void AttachToHost(content::RenderWidgetHost* host);
void DetachFromHost();
// Web view for the web contents managed by this class.
const std::unique_ptr<views::WebView> web_view_;
void OnGotEmbedTokenAndNotify(const base::UnguessableToken& token);
// Web contents managed by this class.
const std::unique_ptr<content::WebContents> web_contents_;
// Web view for the web contents managed by this class.
// Note this is only used for classic ash.
std::unique_ptr<views::WebView> web_view_;
// Current widget host.
content::RenderWidgetHost* host_ = nullptr;
Profile* const profile_; // Unowned
// Token to embed the web contents. On classic ash, it is a token registered
// with AnswerCardContentsRegistry. On mash, it is the embedding token for
// the native window of |web_contents_|.
base::UnguessableToken token_;
// Helper to prepare the native view of |web_contents_| to be embedded under
// mash.
std::unique_ptr<views::RemoteViewProvider> remote_view_provider_;
base::WeakPtrFactory<AnswerCardWebContents> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AnswerCardWebContents);
};
......
......@@ -125,6 +125,7 @@ component("app_list") {
"//ui/resources",
"//ui/strings",
"//ui/views",
"//ui/views/mus/remote_view:remote_view_host",
"//ui/wm",
]
......
......@@ -21,6 +21,7 @@
#include "base/test/icu_test_util.h"
#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/app_list/answer_card_contents_registry.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/pagination_model.h"
#include "ui/app_list/test/app_list_test_model.h"
......@@ -43,6 +44,7 @@
#include "ui/app_list/views/search_result_view.h"
#include "ui/app_list/views/suggestions_container_view.h"
#include "ui/app_list/views/test/apps_grid_view_test_api.h"
#include "ui/aura/env.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/chromeos/search_box/search_box_constants.h"
#include "ui/compositor/layer_animator.h"
......@@ -194,6 +196,19 @@ class AppListViewFocusTest : public views::ViewsTestBase,
base::i18n::SetICUDefaultLocale("he");
}
// Creates AnswerCardContentsRegistry and registers a fake answer card
// view for classic ash. Otherwise, the answer card view will not be
// created. Revisit this when the test runs in mash.
if (aura::Env::GetInstanceDontCreate() &&
aura::Env::GetInstanceDontCreate()->mode() == aura::Env::Mode::LOCAL) {
answer_card_contents_registry_ =
std::make_unique<AnswerCardContentsRegistry>();
fake_answer_card_view_ = std::make_unique<views::View>();
fake_answer_card_view_->set_owned_by_client();
fake_answer_card_token_ = answer_card_contents_registry_->Register(
fake_answer_card_view_.get());
}
// Initialize app list view.
delegate_.reset(new AppListTestViewDelegate);
view_ = new AppListView(delegate_.get());
......@@ -277,6 +292,8 @@ class AppListViewFocusTest : public views::ViewsTestBase,
std::make_unique<TestSearchResult>();
result->set_display_type(data.first);
result->set_relevance(relevance);
if (data.first == ash::SearchResultDisplayType::kCard)
result->set_answer_card_contents_token(fake_answer_card_token_);
results->Add(std::move(result));
}
}
......@@ -461,6 +478,11 @@ class AppListViewFocusTest : public views::ViewsTestBase,
std::unique_ptr<AppsGridViewTestApi> test_api_;
// Restores the locale to default when destructor is called.
base::test::ScopedRestoreICUDefaultLocale restore_locale_;
std::unique_ptr<AnswerCardContentsRegistry> answer_card_contents_registry_;
std::unique_ptr<views::View> fake_answer_card_view_;
base::UnguessableToken fake_answer_card_token_;
DISALLOW_COPY_AND_ASSIGN(AppListViewFocusTest);
};
......
......@@ -8,6 +8,9 @@
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/feature_list.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/app_list/answer_card_contents_registry.h"
......@@ -15,13 +18,45 @@
#include "ui/app_list/app_list_metrics.h"
#include "ui/app_list/app_list_view_delegate.h"
#include "ui/app_list/views/search_result_base_view.h"
#include "ui/base/ui_base_features.h"
#include "ui/gfx/canvas.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/mus/remote_view/remote_view_host.h"
namespace app_list {
namespace {
// Helper to get/create answer card view by token.
views::View* GetViewByToken(const base::UnguessableToken& token) {
// Bail for invalid token.
if (token.is_empty())
return nullptr;
// Use AnswerCardContentsRegistry for an in-process token-to-view map. See
// answer_card_contents_registry.h. Null check because it could be missing in
// Mash and for tests.
if (AnswerCardContentsRegistry::Get())
return AnswerCardContentsRegistry::Get()->GetView(token);
// Use RemoteViewHost to embed the answer card contents provided in the
// browser process in Mash.
if (base::FeatureList::IsEnabled(features::kMash)) {
views::RemoteViewHost* view = new views::RemoteViewHost();
view->EmbedUsingToken(token,
ui::mojom::kEmbedFlagEmbedderInterceptsEvents |
ui::mojom::kEmbedFlagEmbedderControlsVisibility,
base::DoNothing());
return view;
}
return nullptr;
}
} // namespace
// Container of the search answer view.
class SearchResultAnswerCardView::SearchAnswerContainerView
: public SearchResultBaseView {
......@@ -46,9 +81,8 @@ class SearchResultAnswerCardView::SearchAnswerContainerView
bool SetSearchResult(SearchResult* search_result) {
views::View* const old_result_view = child_count() ? child_at(0) : nullptr;
views::View* const new_result_view =
search_result && AnswerCardContentsRegistry::Get()
? AnswerCardContentsRegistry::Get()->GetView(
search_result->answer_card_contents_token())
search_result
? GetViewByToken(search_result->answer_card_contents_token())
: nullptr;
if (old_result_view != new_result_view) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment