Commit d94f7320 authored by Xiyuan Xia's avatar Xiyuan Xia Committed by Commit Bot

Use a token instead of view in SearchResult

Use a token to represent answer card contents since SearchResult data
will go through mojo and views::View* will not work. When app list
search code is in the same process of its ui, AnswerCardCotnentsRegistry
works as a middle man to map token to underlying view. This CL covers
this part. When they are in two processes, the token is the embedding
token that could be used to embed answer card contents in app list ui.
This part will be implemented in a follow-up CL.

Bug: 812434
Change-Id: Ic15bb89c40e370bb3c5967f38efa58828be3967f
Reviewed-on: https://chromium-review.googlesource.com/957742Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543368}
parent 7f9267b5
......@@ -18,6 +18,7 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "extensions/common/constants.h"
#include "ui/app_list/answer_card_contents_registry.h"
#include "ui/app_list/views/app_list_main_view.h"
#include "ui/app_list/views/app_list_view.h"
#include "ui/app_list/views/contents_view.h"
......@@ -59,6 +60,13 @@ AppListControllerImpl::AppListControllerImpl()
std::make_unique<ViewDelegateFactoryImpl>(&view_delegate_)),
this) {
model_.AddObserver(this);
// Create only for non-mash. Mash uses window tree embed API to get a
// token to map answer card contents.
if (Shell::GetAshConfig() != Config::MASH) {
answer_card_contents_registry_ =
std::make_unique<app_list::AnswerCardContentsRegistry>();
}
}
AppListControllerImpl::~AppListControllerImpl() {
......
......@@ -26,6 +26,10 @@ namespace ui {
class MouseWheelEvent;
} // namespace ui
namespace app_list {
class AnswerCardContentsRegistry;
} // namespace app_list
namespace ash {
// Ash's AppListController owns the AppListModel and implements interface
......@@ -145,6 +149,10 @@ class ASH_EXPORT AppListControllerImpl : public mojom::AppListController,
mojom::AppListClientPtr client_;
// Token to view map for classic/mus ash (i.e. non-mash).
std::unique_ptr<app_list::AnswerCardContentsRegistry>
answer_card_contents_registry_;
DISALLOW_COPY_AND_ASSIGN(AppListControllerImpl);
};
......
......@@ -70,7 +70,8 @@ void SearchModel::PublishResults(
for (auto&& new_result : new_results) {
auto ui_result_it = results_map.find(new_result->id());
if (ui_result_it != results_map.end() &&
new_result->view() == ui_result_it->second->view()) {
new_result->answer_card_contents_token() ==
ui_result_it->second->answer_card_contents_token()) {
// Update and use the old result if it exists.
std::unique_ptr<SearchResult> ui_result = std::move(ui_result_it->second);
UpdateResult(new_result.get(), ui_result.get());
......
......@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "base/unguessable_token.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/range/range.h"
......@@ -22,10 +23,6 @@ namespace ui {
class MenuModel;
}
namespace views {
class View;
}
namespace app_list {
class SearchResultObserver;
......@@ -130,8 +127,12 @@ class APP_LIST_MODEL_EXPORT SearchResult {
const base::string16& formatted_price() const { return formatted_price_; }
void SetFormattedPrice(const base::string16& formatted_price);
views::View* view() const { return view_; }
void set_view(views::View* view) { view_ = view; }
const base::UnguessableToken& answer_card_contents_token() const {
return answer_card_contents_token_;
}
void set_answer_card_contents_token(const base::UnguessableToken& token) {
answer_card_contents_token_ = token;
}
const std::string& id() const { return id_; }
const std::string& comparable_id() const { return comparable_id_; }
......@@ -225,11 +226,12 @@ class APP_LIST_MODEL_EXPORT SearchResult {
// Formatted price label of the app in play store. Not exist if set to empty.
base::string16 formatted_price_;
// Unowned pointer to a view containing a rendered result, or nullptr if there
// is no such view for the result.
// The view has set_owned_by_client() property set. It's a responsibility of
// SearchProvider to set this property and own this view.
views::View* view_ = nullptr;
// A token used to show answer card contents. When answer card provider and ui
// runs in the same process (i.e classic ash, or mash before UI migration),
// AnswerCardContensRegistry could be used to map the token to a view.
// Otherwise (mash after UI migration), the token is used to embed the answer
// card contents.
base::UnguessableToken answer_card_contents_token_;
std::string id_;
// ID that can be compared across results from different providers to remove
......
......@@ -6,7 +6,9 @@
#define CHROME_BROWSER_UI_APP_LIST_SEARCH_ANSWER_CARD_ANSWER_CARD_CONTENTS_H_
#include <string>
#include "base/observer_list.h"
#include "base/unguessable_token.h"
class GURL;
......@@ -14,10 +16,6 @@ namespace app_list {
class AnswerCardResult;
}
namespace views {
class View;
}
namespace app_list {
// Abstract source of contents for AnswerCardSearchProvider.
......@@ -49,8 +47,8 @@ class AnswerCardContents {
// Loads contents from |url|.
virtual void LoadURL(const GURL& url) = 0;
// Returns the view associated with the contents.
virtual views::View* GetView() = 0;
// Returns the token associated with the contents.
virtual const base::UnguessableToken& GetToken() const = 0;
// Sets the delegate to process contents-related events.
void SetDelegate(Delegate* delegate);
......
......@@ -4,6 +4,7 @@
#include "chrome/browser/ui/app_list/search/answer_card/answer_card_result.h"
#include "base/unguessable_token.h"
#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
#include "chrome/browser/ui/app_list/search/answer_card/answer_card_contents.h"
#include "chrome/browser/ui/app_list/search/search_util.h"
......@@ -24,7 +25,8 @@ AnswerCardResult::AnswerCardResult(Profile* profile,
set_id(result_url);
set_comparable_id(stripped_result_url);
set_relevance(1);
set_view(contents ? contents->GetView() : nullptr);
set_answer_card_contents_token(contents ? contents->GetToken()
: base::UnguessableToken());
set_title(result_title);
if (contents)
......
......@@ -30,10 +30,10 @@ class AnswerCardTestContents : public AnswerCardContents {
// AnswerCardContents overrides:
void LoadURL(const GURL& url) override { NOTREACHED(); }
views::View* GetView() override { return &view_; }
const base::UnguessableToken& GetToken() const override { return token_; }
private:
views::View view_;
base::UnguessableToken token_;
DISALLOW_COPY_AND_ASSIGN(AnswerCardTestContents);
};
......@@ -59,7 +59,9 @@ class AnswerCardResultTest : public AppListTestBase {
return app_list_controller_delegate_->last_opened_url();
}
views::View* GetView() const { return contents_->GetView(); }
const base::UnguessableToken& GetToken() const {
return contents_->GetToken();
}
// AppListTestBase overrides:
void SetUp() override {
......@@ -86,7 +88,7 @@ TEST_F(AnswerCardResultTest, Basic) {
EXPECT_EQ(base::ASCIIToUTF16(kResultTitle), result->title());
EXPECT_EQ(SearchResult::DISPLAY_CARD, result->display_type());
EXPECT_EQ(1, result->relevance());
EXPECT_EQ(GetView(), result->view());
EXPECT_EQ(GetToken(), result->answer_card_contents_token());
result->Open(ui::EF_NONE);
EXPECT_EQ(kResultUrl, GetLastOpenedUrl().spec());
......@@ -97,7 +99,7 @@ TEST_F(AnswerCardResultTest, Basic) {
EXPECT_EQ(base::ASCIIToUTF16(kResultTitle), result1->title());
EXPECT_EQ(SearchResult::DISPLAY_CARD, result1->display_type());
EXPECT_EQ(1, result1->relevance());
EXPECT_EQ(GetView(), result1->view());
EXPECT_EQ(GetToken(), result1->answer_card_contents_token());
}
TEST_F(AnswerCardResultTest, NullContents) {
......
......@@ -15,6 +15,7 @@
#include "base/metrics/field_trial_params.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/app_list/app_list_test_util.h"
#include "chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h"
......@@ -25,7 +26,6 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/app_list/app_list_features.h"
#include "ui/views/view.h"
using ::testing::_;
using ::testing::Return;
......@@ -62,7 +62,7 @@ class MockAnswerCardContents : public AnswerCardContents {
// AnswerCardContents overrides:
MOCK_METHOD1(LoadURL, void(const GURL& url));
MOCK_METHOD0(GetView, views::View*());
MOCK_CONST_METHOD0(GetToken, const base::UnguessableToken&());
private:
DISALLOW_COPY_AND_ASSIGN(MockAnswerCardContents);
......@@ -103,7 +103,7 @@ class AnswerCardSearchProviderTest : public AppListTestBase {
void VerifyResult(const std::string& message,
const std::string& id,
views::View* view,
const base::UnguessableToken& token,
const std::string& title) {
SCOPED_TRACE(message);
......@@ -112,7 +112,7 @@ class AnswerCardSearchProviderTest : public AppListTestBase {
EXPECT_EQ(SearchResult::DISPLAY_CARD, result->display_type());
EXPECT_EQ(id, result->id());
EXPECT_EQ(1, result->relevance());
EXPECT_EQ(view, result->view());
EXPECT_EQ(token, result->answer_card_contents_token());
EXPECT_EQ(base::UTF8ToUTF16(title), result->title());
}
......@@ -127,8 +127,8 @@ class AnswerCardSearchProviderTest : public AppListTestBase {
AnswerCardSearchProvider* provider() const { return provider_.get(); }
views::View* view0() { return &view0_; }
views::View* view1() { return &view1_; }
const base::UnguessableToken& token0() const { return token0_; }
const base::UnguessableToken& token1() const { return token1_; }
// AppListTestBase overrides:
void SetUp() override {
......@@ -164,8 +164,11 @@ class AnswerCardSearchProviderTest : public AppListTestBase {
profile_.get(), model_updater_.get(), nullptr, std::move(contents0),
std::move(contents1));
ON_CALL(*contents0_, GetView()).WillByDefault(Return(view0()));
ON_CALL(*contents1_, GetView()).WillByDefault(Return(view1()));
token0_ = base::UnguessableToken::Create();
token1_ = base::UnguessableToken::Create();
ON_CALL(*contents0_, GetToken()).WillByDefault(ReturnRef(token0()));
ON_CALL(*contents1_, GetToken()).WillByDefault(ReturnRef(token1()));
}
private:
......@@ -176,8 +179,8 @@ class AnswerCardSearchProviderTest : public AppListTestBase {
MockAnswerCardContents* contents1_ = nullptr; // Unowned.
base::FieldTrialList field_trial_list_;
base::test::ScopedFeatureList scoped_feature_list_;
views::View view0_;
views::View view1_;
base::UnguessableToken token0_;
base::UnguessableToken token1_;
DISALLOW_COPY_AND_ASSIGN(AnswerCardSearchProviderTest);
};
......@@ -190,7 +193,7 @@ TEST_F(AnswerCardSearchProviderTest, Basic) {
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
VerifyResult("Basic Result", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Basic Result", kCatCardId, token1(), kCatCardTitle);
// Now an empty query.
EXPECT_CALL(*contents0(), LoadURL(_)).Times(0);
......@@ -214,41 +217,41 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueries) {
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
VerifyResult("Cat Result 1", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
// 2. Fetch for dog.
// Starting another (dog) search doesn't dismiss the cat card.
EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
provider()->Start(base::UTF8ToUTF16(kDogQuery));
VerifyResult("Cat Result 2", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 2", kCatCardId, token1(), kCatCardTitle);
provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), false,
true, kDogCardTitle, kDogQuery);
// The cat still stays.
VerifyResult("Cat Result 3", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 3", kCatCardId, token1(), kCatCardTitle);
provider()->DidStopLoading(contents0());
// Once the dog finishes loading, it replaces the cat.
VerifyResult("Dog Result 1", kDogCardId, view0(), kDogCardTitle);
VerifyResult("Dog Result 1", kDogCardId, token0(), kDogCardTitle);
// 3. Fetch for shark.
// The third query will use contents1/view1 again.
// The third query will use contents1/token1 again.
EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kSharkQuery)));
provider()->Start(base::UTF8ToUTF16(kSharkQuery));
VerifyResult("Dog Result 2", kDogCardId, view0(), kDogCardTitle);
VerifyResult("Dog Result 2", kDogCardId, token0(), kDogCardTitle);
provider()->DidFinishNavigation(contents1(), GetSearchUrl(kSharkQuery), false,
true, kSharkCardTitle, kSharkQuery);
VerifyResult("Dog Result 3", kDogCardId, view0(), kDogCardTitle);
VerifyResult("Dog Result 3", kDogCardId, token0(), kDogCardTitle);
provider()->DidStopLoading(contents1());
VerifyResult("Shark Result", kSharkCardId, view1(), kSharkCardTitle);
VerifyResult("Shark Result", kSharkCardId, token1(), kSharkCardTitle);
}
// Three queries in a row, second one fails due to an error.
......@@ -260,13 +263,13 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondErrors) {
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
VerifyResult("Cat Result 1", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
// 2. Fetch for dog. This will fail with an error.
EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
provider()->Start(base::UTF8ToUTF16(kDogQuery));
VerifyResult("Cat Result 2", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 2", kCatCardId, token1(), kCatCardTitle);
provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), true,
false, "", "");
......@@ -290,7 +293,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondErrors) {
provider()->DidStopLoading(contents0());
VerifyResult("Shark Result", kSharkCardId, view0(), kSharkCardTitle);
VerifyResult("Shark Result", kSharkCardId, token0(), kSharkCardTitle);
}
// Three queries in a row, second one fails because the server responds with no
......@@ -303,13 +306,13 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondNoCard) {
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
VerifyResult("Cat Result 1", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
// 2. Fetch for dog. This will fail with an error.
EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
provider()->Start(base::UTF8ToUTF16(kDogQuery));
VerifyResult("Cat Result 2", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 2", kCatCardId, token1(), kCatCardTitle);
provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), false,
false, "", "");
......@@ -333,7 +336,7 @@ TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondNoCard) {
provider()->DidStopLoading(contents0());
VerifyResult("Shark Result", kSharkCardId, view0(), kSharkCardTitle);
VerifyResult("Shark Result", kSharkCardId, token0(), kSharkCardTitle);
}
// User enters a query character by character, so that each next query generates
......@@ -366,7 +369,7 @@ TEST_F(AnswerCardSearchProviderTest, InterruptedRequest) {
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
VerifyResult("Cat Result", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result", kCatCardId, token1(), kCatCardTitle);
}
// After seeing a result, the user enters a query character by character. The
......@@ -378,40 +381,40 @@ TEST_F(AnswerCardSearchProviderTest, InterruptedRequestAfterResult) {
true, kCatCardTitle, kCatQuery);
provider()->DidStopLoading(contents1());
VerifyResult("Cat Result 1", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 1", kCatCardId, token1(), kCatCardTitle);
EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl("d")));
provider()->Start(base::UTF8ToUTF16("d"));
VerifyResult("Cat Result 2", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 2", kCatCardId, token1(), kCatCardTitle);
EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl("do")));
provider()->Start(base::UTF8ToUTF16("do"));
VerifyResult("Cat Result 3", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 3", kCatCardId, token1(), kCatCardTitle);
EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
provider()->Start(base::UTF8ToUTF16(kDogQuery));
VerifyResult("Cat Result 4", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 4", kCatCardId, token1(), kCatCardTitle);
provider()->DidFinishNavigation(contents0(), GetSearchUrl("d"), false, true,
"Title d", "d");
provider()->DidStopLoading(contents0());
VerifyResult("Cat Result 5", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 5", kCatCardId, token1(), kCatCardTitle);
provider()->DidFinishNavigation(contents0(), GetSearchUrl("do"), false, true,
"Title do", "do");
provider()->DidStopLoading(contents0());
VerifyResult("Cat Result 5", kCatCardId, view1(), kCatCardTitle);
VerifyResult("Cat Result 5", kCatCardId, token1(), kCatCardTitle);
provider()->DidFinishNavigation(contents0(), GetSearchUrl(kDogQuery), false,
true, kDogCardTitle, kDogQuery);
provider()->DidStopLoading(contents0());
VerifyResult("Dog Result", kDogCardId, view0(), kDogCardTitle);
VerifyResult("Dog Result", kDogCardId, token0(), kDogCardTitle);
}
// Various values for DidFinishNavigation params.
......
......@@ -19,6 +19,7 @@
#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/answer_card_contents_registry.h"
#include "ui/app_list/views/app_list_view.h"
#include "ui/aura/window.h"
#include "ui/views/controls/native/native_view_host.h"
......@@ -159,9 +160,15 @@ AnswerCardWebContents::AnswerCardWebContents(Profile* profile)
content::RenderViewHost* const rvh = web_contents_->GetRenderViewHost();
if (rvh)
AttachToHost(rvh->GetWidget());
if (AnswerCardContentsRegistry::Get())
token_ = AnswerCardContentsRegistry::Get()->Register(web_view_.get());
}
AnswerCardWebContents::~AnswerCardWebContents() {
if (AnswerCardContentsRegistry::Get() && !token_.is_empty())
AnswerCardContentsRegistry::Get()->Unregister(token_);
DetachFromHost();
web_contents_->SetDelegate(nullptr);
Observe(nullptr);
......@@ -177,8 +184,8 @@ void AnswerCardWebContents::LoadURL(const GURL& url) {
gfx::Size(1, 1), gfx::Size(INT_MAX, INT_MAX));
}
views::View* AnswerCardWebContents::GetView() {
return web_view_.get();
const base::UnguessableToken& AnswerCardWebContents::GetToken() const {
return token_;
}
void AnswerCardWebContents::ResizeDueToAutoResize(
......
......@@ -7,6 +7,7 @@
#include <memory>
#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"
#include "content/public/browser/web_contents_delegate.h"
......@@ -30,7 +31,7 @@ class AnswerCardWebContents : public AnswerCardContents,
// AnswerCardContents overrides:
void LoadURL(const GURL& url) override;
views::View* GetView() override;
const base::UnguessableToken& GetToken() const override;
// content::WebContentsDelegate overrides:
void ResizeDueToAutoResize(content::WebContents* web_contents,
......@@ -65,6 +66,8 @@ class AnswerCardWebContents : public AnswerCardContents,
Profile* const profile_; // Unowned
base::UnguessableToken token_;
DISALLOW_COPY_AND_ASSIGN(AnswerCardWebContents);
};
......
......@@ -9,6 +9,8 @@ assert(is_chromeos)
component("app_list") {
sources = [
"answer_card_contents_registry.cc",
"answer_card_contents_registry.h",
"app_list_constants.cc",
"app_list_constants.h",
"app_list_export.h",
......
// Copyright 2018 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 "ui/app_list/answer_card_contents_registry.h"
#include "base/logging.h"
namespace app_list {
namespace {
AnswerCardContentsRegistry* instance = nullptr;
} // namespace
AnswerCardContentsRegistry::AnswerCardContentsRegistry() {
DCHECK(!instance);
instance = this;
}
AnswerCardContentsRegistry::~AnswerCardContentsRegistry() {
DCHECK_EQ(this, instance);
instance = nullptr;
}
// static
AnswerCardContentsRegistry* AnswerCardContentsRegistry::Get() {
return instance;
}
base::UnguessableToken AnswerCardContentsRegistry::Register(
views::View* contents_view) {
const base::UnguessableToken token = base::UnguessableToken::Create();
contents_map_[token] = contents_view;
return token;
}
void AnswerCardContentsRegistry::Unregister(
const base::UnguessableToken& token) {
auto it = contents_map_.find(token);
if (it == contents_map_.end())
return;
contents_map_.erase(it);
}
views::View* AnswerCardContentsRegistry::GetView(
const base::UnguessableToken& token) {
auto it = contents_map_.find(token);
if (it == contents_map_.end())
return nullptr;
return it->second;
}
} // namespace app_list
// Copyright 2018 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.
#ifndef UI_APP_LIST_ANSWER_CARD_CONTENTS_REGISTRY_H_
#define UI_APP_LIST_ANSWER_CARD_CONTENTS_REGISTRY_H_
#include <map>
#include "base/macros.h"
#include "base/unguessable_token.h"
#include "ui/app_list/app_list_export.h"
namespace views {
class View;
}
namespace app_list {
// Helper class to provide a token to answer card view map when app list UI code
// runs in the same process of answer card provider (classic ash, or mash before
// UI code is migrated to ash). In such environment, chrome creates and owns an
// instance of this class. AnswerCardContents registers answer card contents
// with it and get a token back. App list UI code gets the token and use it to
// look up the view to show. On mash after the UI code migration, this class
// will NOT be used at all. App list UI code would use the token to embed the
// answer card content directly.
class APP_LIST_EXPORT AnswerCardContentsRegistry {
public:
AnswerCardContentsRegistry();
~AnswerCardContentsRegistry();
static AnswerCardContentsRegistry* Get();
// Register content with a View.
base::UnguessableToken Register(views::View* contents_view);
// Unregister and release the associated resources.
void Unregister(const base::UnguessableToken& token);
// Get the view for the given token. Return nullptr for unknown token.
views::View* GetView(const base::UnguessableToken& token);
private:
std::map<base::UnguessableToken, views::View*> contents_map_;
DISALLOW_COPY_AND_ASSIGN(AnswerCardContentsRegistry);
};
} // namespace app_list
#endif // UI_APP_LIST_ANSWER_CARD_CONTENTS_REGISTRY_H_
......@@ -10,6 +10,7 @@
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/app_list/answer_card_contents_registry.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/app_list_metrics.h"
#include "ui/app_list/app_list_view_delegate.h"
......@@ -45,7 +46,10 @@ 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 ? search_result->view() : nullptr;
search_result && AnswerCardContentsRegistry::Get()
? AnswerCardContentsRegistry::Get()->GetView(
search_result->answer_card_contents_token())
: nullptr;
if (old_result_view != new_result_view) {
if (old_result_view != nullptr)
......
......@@ -10,7 +10,9 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/unguessable_token.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/app_list/answer_card_contents_registry.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/test/app_list_test_view_delegate.h"
#include "ui/app_list/test/test_search_result.h"
......@@ -43,6 +45,7 @@ class SearchResultAnswerCardViewTest : public views::ViewsTestBase {
result_view_ = std::make_unique<views::View>();
result_view_->set_owned_by_client();
token_ = contents_registry_.Register(result_view_.get());
SetUpSearchResult();
}
......@@ -54,7 +57,7 @@ class SearchResultAnswerCardViewTest : public views::ViewsTestBase {
std::make_unique<TestSearchResult>();
result->set_display_type(SearchResult::DISPLAY_CARD);
result->set_title(base::UTF8ToUTF16(kResultTitle));
result->set_view(result_view_.get());
result->set_answer_card_contents_token(token_);
result->set_relevance(kRelevance);
results->Add(std::move(result));
......@@ -117,6 +120,9 @@ class SearchResultAnswerCardViewTest : public views::ViewsTestBase {
// result_container_view_. Has set_owned_by_client() called.
std::unique_ptr<views::View> result_view_;
AnswerCardContentsRegistry contents_registry_;
base::UnguessableToken token_;
DISALLOW_COPY_AND_ASSIGN(SearchResultAnswerCardViewTest);
};
......
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