Commit 1b2db85e authored by David Black's avatar David Black Committed by Commit Bot

Use Content Service for Assistant cards.

Previously Assistant cards were rendered using WebContentsManager.
This did not support either single- or multi-process mash.

After this CL, I'll do a follow up to remove WebContentsManager and
AnswerCardContentsRegistry as they are no longer used by either
Assistant nor AppList.

Known issue: This works fine for single-process mash but a crash
occurs in multi-process mash when testing on device. No crash occurs
with a glinux build so need to do more debugging. That said, this
still moves us forward and allows us to deprecate some classes :)

Bug: b:78078693
Change-Id: Iae0e9de8e5291f0ac99bae12207483838ccb910e
Reviewed-on: https://chromium-review.googlesource.com/c/1321861
Commit-Queue: David Black <dmblack@google.com>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@google.com>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607030}
parent 1b2bc235
...@@ -181,7 +181,6 @@ component("ash") { ...@@ -181,7 +181,6 @@ component("ash") {
"assistant/model/assistant_query.h", "assistant/model/assistant_query.h",
"assistant/model/assistant_response.cc", "assistant/model/assistant_response.cc",
"assistant/model/assistant_response.h", "assistant/model/assistant_response.h",
"assistant/model/assistant_response_observer.h",
"assistant/model/assistant_screen_context_model.cc", "assistant/model/assistant_screen_context_model.cc",
"assistant/model/assistant_screen_context_model.h", "assistant/model/assistant_screen_context_model.h",
"assistant/model/assistant_screen_context_model_observer.h", "assistant/model/assistant_screen_context_model_observer.h",
......
...@@ -243,25 +243,6 @@ void AssistantInteractionController::OnResponseChanged( ...@@ -243,25 +243,6 @@ void AssistantInteractionController::OnResponseChanged(
assistant_controller_->ui_controller()->model()->entry_point()); assistant_controller_->ui_controller()->model()->entry_point());
} }
void AssistantInteractionController::OnResponseDestroying(
AssistantResponse& response) {
response.RemoveObserver(this);
// We need to explicitly clean up resources owned by WebContentsManager for
// any card elements belonging to the response being destroyed.
std::vector<base::UnguessableToken> id_tokens;
for (const auto& ui_element : response.GetUiElements()) {
if (ui_element->GetType() == AssistantUiElementType::kCard) {
id_tokens.push_back(
static_cast<const AssistantCardElement*>(ui_element.get())
->id_token());
}
}
if (!id_tokens.empty())
assistant_controller_->ReleaseWebContents(id_tokens);
}
void AssistantInteractionController::OnInteractionStarted( void AssistantInteractionController::OnInteractionStarted(
bool is_voice_interaction) { bool is_voice_interaction) {
if (is_voice_interaction) { if (is_voice_interaction) {
...@@ -299,10 +280,8 @@ void AssistantInteractionController::OnInteractionStarted( ...@@ -299,10 +280,8 @@ void AssistantInteractionController::OnInteractionStarted(
model_.SetMicState(MicState::kClosed); model_.SetMicState(MicState::kClosed);
} }
// Start caching a new Assistant response for the interaction. We observe the // Start caching a new Assistant response for the interaction.
// response so that we can receive notification of lifecycle change events.
model_.SetPendingResponse(std::make_unique<AssistantResponse>()); model_.SetPendingResponse(std::make_unique<AssistantResponse>());
model_.pending_response()->AddObserver(this);
} }
void AssistantInteractionController::OnInteractionFinished( void AssistantInteractionController::OnInteractionFinished(
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "ash/assistant/assistant_response_processor.h" #include "ash/assistant/assistant_response_processor.h"
#include "ash/assistant/model/assistant_interaction_model.h" #include "ash/assistant/model/assistant_interaction_model.h"
#include "ash/assistant/model/assistant_interaction_model_observer.h" #include "ash/assistant/model/assistant_interaction_model_observer.h"
#include "ash/assistant/model/assistant_response_observer.h"
#include "ash/assistant/model/assistant_ui_model_observer.h" #include "ash/assistant/model/assistant_ui_model_observer.h"
#include "ash/assistant/ui/dialog_plate/dialog_plate.h" #include "ash/assistant/ui/dialog_plate/dialog_plate.h"
#include "ash/highlighter/highlighter_controller.h" #include "ash/highlighter/highlighter_controller.h"
...@@ -33,7 +32,6 @@ class AssistantInteractionController ...@@ -33,7 +32,6 @@ class AssistantInteractionController
: public chromeos::assistant::mojom::AssistantInteractionSubscriber, : public chromeos::assistant::mojom::AssistantInteractionSubscriber,
public AssistantControllerObserver, public AssistantControllerObserver,
public AssistantInteractionModelObserver, public AssistantInteractionModelObserver,
public AssistantResponseObserver,
public AssistantUiModelObserver, public AssistantUiModelObserver,
public HighlighterController::Observer, public HighlighterController::Observer,
public DialogPlateObserver { public DialogPlateObserver {
...@@ -72,9 +70,6 @@ class AssistantInteractionController ...@@ -72,9 +70,6 @@ class AssistantInteractionController
void OnResponseChanged( void OnResponseChanged(
const std::shared_ptr<AssistantResponse>& response) override; const std::shared_ptr<AssistantResponse>& response) override;
// AssistantResponseObserver:
void OnResponseDestroying(AssistantResponse& response) override;
// AssistantUiModelObserver: // AssistantUiModelObserver:
void OnUiModeChanged(AssistantUiMode ui_mode) override; void OnUiModeChanged(AssistantUiMode ui_mode) override;
void OnUiVisibilityChanged(AssistantVisibility new_visibility, void OnUiVisibilityChanged(AssistantVisibility new_visibility,
......
...@@ -4,11 +4,14 @@ ...@@ -4,11 +4,14 @@
#include "ash/assistant/assistant_response_processor.h" #include "ash/assistant/assistant_response_processor.h"
#include <algorithm>
#include "ash/assistant/assistant_controller.h" #include "ash/assistant/assistant_controller.h"
#include "ash/assistant/model/assistant_response.h" #include "ash/assistant/model/assistant_response.h"
#include "ash/assistant/model/assistant_ui_element.h" #include "ash/assistant/model/assistant_ui_element.h"
#include "ash/assistant/ui/assistant_ui_constants.h" #include "ash/assistant/ui/assistant_ui_constants.h"
#include "base/base64.h" #include "base/base64.h"
#include "base/stl_util.h"
namespace ash { namespace ash {
...@@ -19,6 +22,56 @@ constexpr char kDataUriPrefix[] = "data:text/html;base64,"; ...@@ -19,6 +22,56 @@ constexpr char kDataUriPrefix[] = "data:text/html;base64,";
} // namespace } // namespace
// AssistantCardProcessor ------------------------------------------------------
AssistantCardProcessor::AssistantCardProcessor(
AssistantController* assistant_controller,
AssistantResponseProcessor* assistant_response_processor,
AssistantCardElement* assistant_card_element)
: assistant_controller_(assistant_controller),
assistant_response_processor_(assistant_response_processor),
assistant_card_element_(assistant_card_element) {}
AssistantCardProcessor::~AssistantCardProcessor() {
if (contents_)
contents_->RemoveObserver(this);
}
void AssistantCardProcessor::DidStopLoading() {
contents_->RemoveObserver(this);
// Transfer ownership of |contents_| to the card element and notify the
// response processor that we've finished processing.
assistant_card_element_->set_contents(std::move(contents_));
assistant_response_processor_->DidFinishProcessing(this);
}
void AssistantCardProcessor::Process() {
assistant_controller_->GetNavigableContentsFactory(
mojo::MakeRequest(&contents_factory_));
// TODO(dmblack): Find a better way of determining desired card size.
const int width_dip = kPreferredWidthDip - 2 * kUiElementHorizontalMarginDip;
// Configure parameters for the card.
auto contents_params = content::mojom::NavigableContentsParams::New();
contents_params->enable_view_auto_resize = true;
contents_params->auto_resize_min_size = gfx::Size(width_dip, 1);
contents_params->auto_resize_max_size = gfx::Size(width_dip, INT_MAX);
contents_params->suppress_navigations = true;
contents_ = std::make_unique<content::NavigableContents>(
contents_factory_.get(), std::move(contents_params));
// Observe |contents_| so that we are notified when loading is complete.
contents_->AddObserver(this);
// Navigate to the data URL which represents the card.
std::string encoded_html;
base::Base64Encode(assistant_card_element_->html(), &encoded_html);
contents_->Navigate(GURL(kDataUriPrefix + encoded_html));
}
// AssistantResponseProcessor::Task -------------------------------------------- // AssistantResponseProcessor::Task --------------------------------------------
AssistantResponseProcessor::Task::Task(AssistantResponse& response, AssistantResponseProcessor::Task::Task(AssistantResponse& response,
...@@ -57,8 +110,12 @@ void AssistantResponseProcessor::Process(AssistantResponse& response, ...@@ -57,8 +110,12 @@ void AssistantResponseProcessor::Process(AssistantResponse& response,
for (const auto& ui_element : response.GetUiElements()) { for (const auto& ui_element : response.GetUiElements()) {
switch (ui_element->GetType()) { switch (ui_element->GetType()) {
case AssistantUiElementType::kCard: case AssistantUiElementType::kCard:
ProcessCardElement( // Create and start an element processor to process the card element.
static_cast<AssistantCardElement*>(ui_element.get())); task_->element_processors.push_back(
std::make_unique<AssistantCardProcessor>(
assistant_controller_, this,
static_cast<AssistantCardElement*>(ui_element.get())));
task_->element_processors.back()->Process();
break; break;
case AssistantUiElementType::kText: case AssistantUiElementType::kText:
// No processing necessary. // No processing necessary.
...@@ -71,49 +128,20 @@ void AssistantResponseProcessor::Process(AssistantResponse& response, ...@@ -71,49 +128,20 @@ void AssistantResponseProcessor::Process(AssistantResponse& response,
TryFinishingTask(); TryFinishingTask();
} }
void AssistantResponseProcessor::ProcessCardElement( void AssistantResponseProcessor::DidFinishProcessing(
AssistantCardElement* card_element) { const AssistantCardProcessor* card_processor) {
// Encode the card HTML using base64.
std::string encoded_html;
base::Base64Encode(card_element->html(), &encoded_html);
// TODO(dmblack): Find a better way of determining desired card size.
const int width_dip = kPreferredWidthDip - 2 * kUiElementHorizontalMarginDip;
// Configure parameters for the card.
ash::mojom::ManagedWebContentsParamsPtr params(
ash::mojom::ManagedWebContentsParams::New());
params->url = GURL(kDataUriPrefix + encoded_html);
params->min_size_dip = gfx::Size(width_dip, 0);
params->max_size_dip = gfx::Size(width_dip, INT_MAX);
// Request an embed token for the card whose WebContents will be owned by
// WebContentsManager.
assistant_controller_->ManageWebContents(
card_element->id_token(), std::move(params),
base::BindOnce(&AssistantResponseProcessor::OnCardElementProcessed,
weak_factory_.GetWeakPtr(), card_element));
// Increment |processing_count| to reflect the fact that a card element is
// being processed asynchronously.
++task_->processing_count;
}
void AssistantResponseProcessor::OnCardElementProcessed(
AssistantCardElement* card_element,
const base::Optional<base::UnguessableToken>& embed_token) {
// If the response has been invalidated we should abort early. // If the response has been invalidated we should abort early.
if (!task_->response) { if (!task_->response) {
TryAbortingTask(); TryAbortingTask();
return; return;
} }
// Save the |embed_token|. // Remove the finished element processor to indicate its completion.
card_element->set_embed_token(embed_token); base::EraseIf(task_->element_processors,
[card_processor](
// Decrement |processing_count| to reflect the fact that a card element has const std::unique_ptr<AssistantCardProcessor>& candidate) {
// finished being processed asynchronously. return candidate.get() == card_processor;
--task_->processing_count; });
// Try finishing. This will no-op if there are still UI elements being // Try finishing. This will no-op if there are still UI elements being
// processed asynchronously. // processed asynchronously.
...@@ -135,7 +163,7 @@ void AssistantResponseProcessor::TryAbortingTask() { ...@@ -135,7 +163,7 @@ void AssistantResponseProcessor::TryAbortingTask() {
void AssistantResponseProcessor::TryFinishingTask() { void AssistantResponseProcessor::TryFinishingTask() {
// This method is a no-op if we are still processing. // This method is a no-op if we are still processing.
if (task_->processing_count > 0) if (!task_->element_processors.empty())
return; return;
// Update processing state. // Update processing state.
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "services/content/public/cpp/navigable_contents.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
namespace ash { namespace ash {
...@@ -21,8 +22,42 @@ namespace ash { ...@@ -21,8 +22,42 @@ namespace ash {
class AssistantController; class AssistantController;
class AssistantCardElement; class AssistantCardElement;
class AssistantResponse; class AssistantResponse;
class AssistantResponseProcessor;
enum class AssistantUiElementType; enum class AssistantUiElementType;
// AssistantCardProcessor ------------------------------------------------------
// A UI element processor associated with a single card element that is
// responsible for processing an Assistant card on behalf of an
// AssistantResponseProcessor.
class AssistantCardProcessor : public content::NavigableContentsObserver {
public:
AssistantCardProcessor(
AssistantController* assistant_controller,
AssistantResponseProcessor* assistant_response_processor,
AssistantCardElement* assistant_card_element);
~AssistantCardProcessor() override;
// content::NavigableContentsObserver:
void DidStopLoading() override;
// Starts processing the associated card element. Upon completion, this
// processor will call DidFinishProcessing on |assistant_response_processor_|.
void Process();
private:
AssistantController* const assistant_controller_;
AssistantResponseProcessor* const assistant_response_processor_;
AssistantCardElement* const assistant_card_element_;
content::mojom::NavigableContentsFactoryPtr contents_factory_;
std::unique_ptr<content::NavigableContents> contents_;
DISALLOW_COPY_AND_ASSIGN(AssistantCardProcessor);
};
// AssistantResponseProcessor --------------------------------------------------
// The AssistantResponseProcessor is responsible for performing any processing // The AssistantResponseProcessor is responsible for performing any processing
// steps necessary on an Assistant response before it is ready for presentation. // steps necessary on an Assistant response before it is ready for presentation.
class AssistantResponseProcessor { class AssistantResponseProcessor {
...@@ -39,6 +74,9 @@ class AssistantResponseProcessor { ...@@ -39,6 +74,9 @@ class AssistantResponseProcessor {
// while another response is being processed will abort the previous task. // while another response is being processed will abort the previous task.
void Process(AssistantResponse& response, ProcessCallback callback); void Process(AssistantResponse& response, ProcessCallback callback);
// Invoked when the specified |card_processor| has finished processing.
void DidFinishProcessing(const AssistantCardProcessor* card_processor);
private: private:
// Encapsulates a processing task for a given Assistant response. Upon task // Encapsulates a processing task for a given Assistant response. Upon task
// abort/completion, the associated callback should be run. // abort/completion, the associated callback should be run.
...@@ -53,8 +91,10 @@ class AssistantResponseProcessor { ...@@ -53,8 +91,10 @@ class AssistantResponseProcessor {
// Callback to be run on task abort/completion. // Callback to be run on task abort/completion.
ProcessCallback callback; ProcessCallback callback;
// Count of UI elements that are being asynchronously processed. // Vector of element processors that are processing the UI elements
int processing_count = 0; // contained in |response|. When |element_processors| is empty, response
// processing is complete.
std::vector<std::unique_ptr<AssistantCardProcessor>> element_processors;
}; };
// Processes a card element as a part of the task identified by |task_id|. // Processes a card element as a part of the task identified by |task_id|.
......
...@@ -4,24 +4,13 @@ ...@@ -4,24 +4,13 @@
#include "ash/assistant/model/assistant_response.h" #include "ash/assistant/model/assistant_response.h"
#include "ash/assistant/model/assistant_response_observer.h"
#include "ash/assistant/model/assistant_ui_element.h" #include "ash/assistant/model/assistant_ui_element.h"
namespace ash { namespace ash {
AssistantResponse::AssistantResponse() : weak_factory_(this) {} AssistantResponse::AssistantResponse() : weak_factory_(this) {}
AssistantResponse::~AssistantResponse() { AssistantResponse::~AssistantResponse() = default;
NotifyDestroying();
}
void AssistantResponse::AddObserver(AssistantResponseObserver* observer) {
observers_.AddObserver(observer);
}
void AssistantResponse::RemoveObserver(AssistantResponseObserver* observer) {
observers_.RemoveObserver(observer);
}
void AssistantResponse::AddUiElement( void AssistantResponse::AddUiElement(
std::unique_ptr<AssistantUiElement> ui_element) { std::unique_ptr<AssistantUiElement> ui_element) {
...@@ -65,9 +54,4 @@ base::WeakPtr<AssistantResponse> AssistantResponse::GetWeakPtr() { ...@@ -65,9 +54,4 @@ base::WeakPtr<AssistantResponse> AssistantResponse::GetWeakPtr() {
return weak_factory_.GetWeakPtr(); return weak_factory_.GetWeakPtr();
} }
void AssistantResponse::NotifyDestroying() {
for (auto& observer : observers_)
observer.OnResponseDestroying(*this);
}
} // namespace ash } // namespace ash
\ No newline at end of file
...@@ -11,12 +11,10 @@ ...@@ -11,12 +11,10 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chromeos/services/assistant/public/mojom/assistant.mojom.h" #include "chromeos/services/assistant/public/mojom/assistant.mojom.h"
namespace ash { namespace ash {
class AssistantResponseObserver;
class AssistantUiElement; class AssistantUiElement;
// Models a renderable Assistant response. // Models a renderable Assistant response.
...@@ -35,10 +33,6 @@ class AssistantResponse { ...@@ -35,10 +33,6 @@ class AssistantResponse {
AssistantResponse(); AssistantResponse();
~AssistantResponse(); ~AssistantResponse();
// Adds/removes the specified |observer|.
void AddObserver(AssistantResponseObserver* observer);
void RemoveObserver(AssistantResponseObserver* observer);
// Adds the specified |ui_element| that should be rendered for the // Adds the specified |ui_element| that should be rendered for the
// interaction. // interaction.
void AddUiElement(std::unique_ptr<AssistantUiElement> ui_element); void AddUiElement(std::unique_ptr<AssistantUiElement> ui_element);
...@@ -71,15 +65,11 @@ class AssistantResponse { ...@@ -71,15 +65,11 @@ class AssistantResponse {
base::WeakPtr<AssistantResponse> GetWeakPtr(); base::WeakPtr<AssistantResponse> GetWeakPtr();
private: private:
void NotifyDestroying();
std::vector<std::unique_ptr<AssistantUiElement>> ui_elements_; std::vector<std::unique_ptr<AssistantUiElement>> ui_elements_;
std::vector<AssistantSuggestionPtr> suggestions_; std::vector<AssistantSuggestionPtr> suggestions_;
ProcessingState processing_state_ = ProcessingState::kUnprocessed; ProcessingState processing_state_ = ProcessingState::kUnprocessed;
bool has_tts_ = false; bool has_tts_ = false;
base::ObserverList<AssistantResponseObserver>::Unchecked observers_;
base::WeakPtrFactory<AssistantResponse> weak_factory_; base::WeakPtrFactory<AssistantResponse> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AssistantResponse); DISALLOW_COPY_AND_ASSIGN(AssistantResponse);
......
// 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 ASH_ASSISTANT_MODEL_ASSISTANT_RESPONSE_OBSERVER_H_
#define ASH_ASSISTANT_MODEL_ASSISTANT_RESPONSE_OBSERVER_H_
#include "base/macros.h"
namespace ash {
class AssistantResponse;
// An observer which receives notification of changes to an Assistant response.
class AssistantResponseObserver {
public:
// Invoked when the specified |response| is being destroyed.
virtual void OnResponseDestroying(AssistantResponse& response) {}
protected:
AssistantResponseObserver() = default;
virtual ~AssistantResponseObserver() = default;
DISALLOW_COPY_AND_ASSIGN(AssistantResponseObserver);
};
} // namespace ash
#endif // ASH_ASSISTANT_MODEL_ASSISTANT_RESPONSE_OBSERVER_H_
...@@ -12,8 +12,7 @@ AssistantCardElement::AssistantCardElement(const std::string& html, ...@@ -12,8 +12,7 @@ AssistantCardElement::AssistantCardElement(const std::string& html,
const std::string& fallback) const std::string& fallback)
: AssistantUiElement(AssistantUiElementType::kCard), : AssistantUiElement(AssistantUiElementType::kCard),
html_(html), html_(html),
fallback_(fallback), fallback_(fallback) {}
id_token_(base::UnguessableToken::Create()) {}
AssistantCardElement::~AssistantCardElement() = default; AssistantCardElement::~AssistantCardElement() = default;
......
...@@ -5,11 +5,11 @@ ...@@ -5,11 +5,11 @@
#ifndef ASH_ASSISTANT_MODEL_ASSISTANT_UI_ELEMENT_H_ #ifndef ASH_ASSISTANT_MODEL_ASSISTANT_UI_ELEMENT_H_
#define ASH_ASSISTANT_MODEL_ASSISTANT_UI_ELEMENT_H_ #define ASH_ASSISTANT_MODEL_ASSISTANT_UI_ELEMENT_H_
#include <memory>
#include <string> #include <string>
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "services/content/public/cpp/navigable_contents.h"
#include "base/unguessable_token.h"
namespace ash { namespace ash {
...@@ -52,22 +52,18 @@ class AssistantCardElement : public AssistantUiElement { ...@@ -52,22 +52,18 @@ class AssistantCardElement : public AssistantUiElement {
const std::string& fallback() const { return fallback_; } const std::string& fallback() const { return fallback_; }
const base::UnguessableToken& id_token() const { return id_token_; } const content::NavigableContents* contents() const { return contents_.get(); }
content::NavigableContents* contents() { return contents_.get(); }
const base::Optional<base::UnguessableToken>& embed_token() const { void set_contents(std::unique_ptr<content::NavigableContents> contents) {
return embed_token_; contents_ = std::move(contents);
}
void set_embed_token(
const base::Optional<base::UnguessableToken>& embed_token) {
embed_token_ = embed_token;
} }
private: private:
const std::string html_; const std::string html_;
const std::string fallback_; const std::string fallback_;
base::UnguessableToken id_token_;
base::Optional<base::UnguessableToken> embed_token_ = base::nullopt; std::unique_ptr<content::NavigableContents> contents_;
DISALLOW_COPY_AND_ASSIGN(AssistantCardElement); DISALLOW_COPY_AND_ASSIGN(AssistantCardElement);
}; };
......
...@@ -14,11 +14,10 @@ ...@@ -14,11 +14,10 @@
#include "ash/assistant/ui/assistant_ui_constants.h" #include "ash/assistant/ui/assistant_ui_constants.h"
#include "ash/assistant/ui/main_stage/assistant_text_element_view.h" #include "ash/assistant/ui/main_stage/assistant_text_element_view.h"
#include "ash/assistant/util/animation_util.h" #include "ash/assistant/util/animation_util.h"
#include "ash/public/cpp/app_list/answer_card_contents_registry.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/unguessable_token.h" #include "services/content/public/cpp/navigable_contents_view.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host.h"
#include "ui/compositor/callback_layer_animation_observer.h" #include "ui/compositor/callback_layer_animation_observer.h"
...@@ -89,14 +88,18 @@ void CreateAndSendMouseClick(aura::WindowTreeHost* host, ...@@ -89,14 +88,18 @@ void CreateAndSendMouseClick(aura::WindowTreeHost* host,
// aura::Window. The child widget's layer becomes the root of the card's layer // aura::Window. The child widget's layer becomes the root of the card's layer
// hierarchy. // hierarchy.
class CardElementViewHolder : public views::NativeViewHost, class CardElementViewHolder : public views::NativeViewHost,
public views::ViewObserver { public views::ViewObserver,
public content::NavigableContentsObserver {
public: public:
explicit CardElementViewHolder(const AssistantCardElement* card_element) CardElementViewHolder(AssistantController* assistant_controller,
: card_element_view_(app_list::AnswerCardContentsRegistry::Get()->GetView( AssistantCardElement* card_element,
card_element->embed_token().value())) { views::Widget* context)
: assistant_controller_(assistant_controller),
contents_(card_element->contents()) {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
params.name = GetClassName(); params.name = GetClassName();
params.context = context->GetNativeWindow();
params.delegate = new views::WidgetDelegateView(); params.delegate = new views::WidgetDelegateView();
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
...@@ -106,17 +109,21 @@ class CardElementViewHolder : public views::NativeViewHost, ...@@ -106,17 +109,21 @@ class CardElementViewHolder : public views::NativeViewHost,
contents_view_ = params.delegate->GetContentsView(); contents_view_ = params.delegate->GetContentsView();
contents_view_->SetLayoutManager(std::make_unique<views::FillLayout>()); contents_view_->SetLayoutManager(std::make_unique<views::FillLayout>());
contents_view_->AddChildView(card_element_view_); contents_view_->AddChildView(contents_->GetView()->view());
card_element_view_->AddObserver(this); // We observe the |contents_| view to receive notification of preferred size
// changes and we observe |contents_| to receive events pertaining to the
// underlying web contents.
contents_->GetView()->view()->AddObserver(this);
contents_->AddObserver(this);
// OverrideDescription() doesn't work. Only names are read automatically. // OverrideDescription() doesn't work. Only names are read automatically.
GetViewAccessibility().OverrideName(card_element->fallback()); GetViewAccessibility().OverrideName(card_element->fallback());
} }
~CardElementViewHolder() override { ~CardElementViewHolder() override {
if (card_element_view_) contents_->GetView()->view()->RemoveObserver(this);
card_element_view_->RemoveObserver(this); contents_->RemoveObserver(this);
} }
// views::NativeViewHost: // views::NativeViewHost:
...@@ -165,21 +172,23 @@ class CardElementViewHolder : public views::NativeViewHost, ...@@ -165,21 +172,23 @@ class CardElementViewHolder : public views::NativeViewHost,
cursor_manager->UnlockCursor(); cursor_manager->UnlockCursor();
} }
// views::ViewObserver: // content::NavigableContentsObserver:
void OnViewIsDeleting(views::View* view) override { void DidAutoResizeView(const gfx::Size& new_size) override {
DCHECK_EQ(card_element_view_, view); contents_->GetView()->view()->SetPreferredSize(new_size);
}
// It's possible for |card_element_view_| to be destroyed before
// CardElementViewHolder. When this happens, we need to perform clean up void DidSuppressNavigation(const GURL& url,
// prior to |card_element_view_| being destroyed and remove our cached WindowOpenDisposition disposition,
// reference to prevent additional clean up attempts on the destroyed bool from_user_gesture) override {
// instance when destroying CardElementViewHolder. // We delegate navigation to the AssistantController so that it can apply
card_element_view_->RemoveObserver(this); // special handling to deep links.
card_element_view_ = nullptr; if (from_user_gesture)
assistant_controller_->OpenUrl(url);
} }
// views::ViewObserver:
void OnViewPreferredSizeChanged(views::View* view) override { void OnViewPreferredSizeChanged(views::View* view) override {
DCHECK_EQ(card_element_view_, view); DCHECK_EQ(contents_->GetView()->view(), view);
gfx::Size preferred_size = view->GetPreferredSize(); gfx::Size preferred_size = view->GetPreferredSize();
...@@ -213,7 +222,10 @@ class CardElementViewHolder : public views::NativeViewHost, ...@@ -213,7 +222,10 @@ class CardElementViewHolder : public views::NativeViewHost,
} }
private: private:
views::View* card_element_view_; // Owned by WebContentsManager. AssistantController* const assistant_controller_; // Owned by Shell.
// Owned by AssistantCardElement.
content::NavigableContents* const contents_;
std::unique_ptr<views::Widget> child_widget_; std::unique_ptr<views::Widget> child_widget_;
...@@ -397,51 +409,47 @@ void UiElementContainerView::OnResponseAdded( ...@@ -397,51 +409,47 @@ void UiElementContainerView::OnResponseAdded(
void UiElementContainerView::OnCardElementAdded( void UiElementContainerView::OnCardElementAdded(
const AssistantCardElement* card_element) { const AssistantCardElement* card_element) {
// The card, for some reason, is not embeddable so we'll have to ignore it. // The card, for some reason, is not embeddable so we'll have to ignore it.
if (!card_element->embed_token().has_value()) if (!card_element->contents())
return; return;
// When the card has been rendered in the same process, its view is auto* view_holder = new CardElementViewHolder(
// available in the AnswerCardContentsRegistry's token-to-view map. assistant_controller_, const_cast<AssistantCardElement*>(card_element),
if (app_list::AnswerCardContentsRegistry::Get()) { /*context=*/GetWidget());
auto* view_holder = new CardElementViewHolder(card_element);
if (is_first_card_) { if (is_first_card_) {
is_first_card_ = false; is_first_card_ = false;
// The first card requires a top margin of |kFirstCardMarginTopDip|, but // The first card requires a top margin of |kFirstCardMarginTopDip|, but
// we need to account for child spacing because the first card is not // we need to account for child spacing because the first card is not
// necessarily the first UI element. // necessarily the first UI element.
const int top_margin_dip = child_count() == 0 const int top_margin_dip = child_count() == 0
? kFirstCardMarginTopDip ? kFirstCardMarginTopDip
: kFirstCardMarginTopDip - kSpacingDip; : kFirstCardMarginTopDip - kSpacingDip;
// We effectively create a top margin by applying an empty border. // We effectively create a top margin by applying an empty border.
view_holder->SetBorder(views::CreateEmptyBorder(top_margin_dip, 0, 0, 0)); view_holder->SetBorder(views::CreateEmptyBorder(top_margin_dip, 0, 0, 0));
}
content_view()->AddChildView(view_holder);
view_holder->Attach();
// Cache a reference to the attached native view host so that it can be
// detached prior to being removed from the view hierarchy and destroyed.
native_view_hosts_.push_back(view_holder);
// The view will be animated on its own layer, so we need to do some initial
// layer setup. We're going to fade the view in, so hide it. Note that we
// approximate 0% opacity by actually using 0.01%. We do this to workaround
// a DCHECK that requires aura::Windows to have a target opacity > 0% when
// shown. Because our window will be animated to full opacity from this
// value, it should be safe to circumnavigate this DCHECK.
view_holder->native_view()->layer()->SetFillsBoundsOpaquely(false);
view_holder->native_view()->layer()->SetOpacity(0.0001f);
// We cache the native view for use during animations and its desired
// opacity that we'll animate to while processing the next query response.
ui_element_views_.push_back(std::pair<ui::LayerOwner*, float>(
view_holder->native_view(), kCardElementAnimationFadeOutOpacity));
} }
// TODO(dmblack): Handle Mash case. content_view()->AddChildView(view_holder);
view_holder->Attach();
// Cache a reference to the attached native view host so that it can be
// detached prior to being removed from the view hierarchy and destroyed.
native_view_hosts_.push_back(view_holder);
// The view will be animated on its own layer, so we need to do some initial
// layer setup. We're going to fade the view in, so hide it. Note that we
// approximate 0% opacity by actually using 0.01%. We do this to workaround
// a DCHECK that requires aura::Windows to have a target opacity > 0% when
// shown. Because our window will be animated to full opacity from this
// value, it should be safe to circumnavigate this DCHECK.
view_holder->native_view()->layer()->SetFillsBoundsOpaquely(false);
view_holder->native_view()->layer()->SetOpacity(0.0001f);
// We cache the native view for use during animations and its desired
// opacity that we'll animate to while processing the next query response.
ui_element_views_.push_back(std::pair<ui::LayerOwner*, float>(
view_holder->native_view(), kCardElementAnimationFadeOutOpacity));
} }
void UiElementContainerView::OnTextElementAdded( void UiElementContainerView::OnTextElementAdded(
......
...@@ -46,8 +46,8 @@ NavigableContentsImpl::~NavigableContentsImpl() = default; ...@@ -46,8 +46,8 @@ NavigableContentsImpl::~NavigableContentsImpl() = default;
void NavigableContentsImpl::Navigate(const GURL& url, void NavigableContentsImpl::Navigate(const GURL& url,
mojom::NavigateParamsPtr params) { mojom::NavigateParamsPtr params) {
// Ignore non-HTTP/HTTPS requests for now. // Ignore non-HTTP/HTTPS/data requests for now.
if (!url.SchemeIsHTTPOrHTTPS()) if (!url.SchemeIsHTTPOrHTTPS() && !url.SchemeIs(url::kDataScheme))
return; return;
delegate_->Navigate(url, std::move(params)); delegate_->Navigate(url, std::move(params));
......
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