Commit b8919fef authored by David Black's avatar David Black Committed by Commit Bot

Don't hide Assistant when opening tabs.

Previously, opening a browser tab would cause Assistant UI to hide.
Now, we'll remain open but go into mini UI mode.

In mini UI mode, we'll show the active query (if there is one) in lieu
of the default prompt string. Stylus behavior remains unchanged.

This CL also adds an AssistantContainerLayout to serve as the layout
manager for AssistantContainerView. This was done to setup for
additional motion specs as well as to fix a crash.

See bug for demo.

Bug: b:112376466
Change-Id: Ia920f3c2509eb6f255d5eb6d508dfb650383773b
Reviewed-on: https://chromium-review.googlesource.com/1168654
Commit-Queue: David Black <dmblack@google.com>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#581972}
parent 936de484
......@@ -197,8 +197,9 @@ void AssistantUiController::OnDeepLinkReceived(
}
void AssistantUiController::OnUrlOpened(const GURL& url) {
// We close Assistant UI when opening a URL in a new tab.
HideUi(AssistantSource::kUnspecified);
// We go into mini UI mode when opening a URL in a new tab.
if (assistant_ui_model_.visible())
UpdateUiMode(AssistantUiMode::kMiniUi);
}
void AssistantUiController::OnUiVisibilityChanged(bool visible,
......
......@@ -4,6 +4,8 @@
#include "ash/assistant/ui/assistant_container_view.h"
#include <memory>
#include "ash/assistant/assistant_controller.h"
#include "ash/assistant/assistant_ui_controller.h"
#include "ash/assistant/model/assistant_ui_model.h"
......@@ -15,7 +17,7 @@
#include "ui/display/screen.h"
#include "ui/views/bubble/bubble_dialog_delegate.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/layout_manager.h"
#include "ui/views/view.h"
#include "ui/wm/core/shadow_types.h"
......@@ -28,8 +30,81 @@ constexpr SkColor kBackgroundColor = SK_ColorWHITE;
constexpr int kCornerRadiusDip = 20;
constexpr int kMarginDip = 8;
// AssistantContainerLayout ----------------------------------------------------
// The AssistantContainerLayout calculates preferred size to fit the largest
// visible child. Children that are not visible are not factored in. During
// layout, children are horizontally centered and bottom aligned.
class AssistantContainerLayout : public views::LayoutManager {
public:
AssistantContainerLayout() = default;
~AssistantContainerLayout() override = default;
// views::LayoutManager:
gfx::Size GetPreferredSize(const views::View* host) const override {
int preferred_width = 0;
for (int i = 0; i < host->child_count(); ++i) {
const views::View* child = host->child_at(i);
// We do not include invisible children in our size calculation.
if (!child->visible())
continue;
// Our preferred width is the width of our largest visible child.
preferred_width =
std::max(child->GetPreferredSize().width(), preferred_width);
}
return gfx::Size(preferred_width,
GetPreferredHeightForWidth(host, preferred_width));
}
int GetPreferredHeightForWidth(const views::View* host,
int width) const override {
int preferred_height = 0;
for (int i = 0; i < host->child_count(); ++i) {
const views::View* child = host->child_at(i);
// We do not include invisible children in our size calculation.
if (!child->visible())
continue;
// Our preferred height is the height of our largest visible child.
preferred_height =
std::max(child->GetHeightForWidth(width), preferred_height);
}
return preferred_height;
}
void Layout(views::View* host) override {
const int host_width = host->width();
const int host_height = host->height();
for (int i = 0; i < host->child_count(); ++i) {
views::View* child = host->child_at(i);
const gfx::Size child_size = child->GetPreferredSize();
// Children are horizontally centered and bottom aligned.
int child_left = (host_width - child_size.width()) / 2;
int child_top = host_height - child_size.height();
child->SetBounds(child_left, child_top, child_size.width(),
child_size.height());
}
}
private:
DISALLOW_COPY_AND_ASSIGN(AssistantContainerLayout);
};
} // namespace
// AssistantContainerView ------------------------------------------------------
AssistantContainerView::AssistantContainerView(
AssistantController* assistant_controller)
: assistant_controller_(assistant_controller) {
......@@ -93,23 +168,20 @@ void AssistantContainerView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
}
void AssistantContainerView::Init() {
SetLayoutManager(std::make_unique<views::FillLayout>());
SetLayoutManager(std::make_unique<AssistantContainerLayout>());
// Main view.
assistant_main_view_ =
std::make_unique<AssistantMainView>(assistant_controller_);
assistant_main_view_->set_owned_by_client();
assistant_main_view_ = new AssistantMainView(assistant_controller_);
AddChildView(assistant_main_view_);
// Mini view.
assistant_mini_view_ =
std::make_unique<AssistantMiniView>(assistant_controller_);
assistant_mini_view_ = new AssistantMiniView(assistant_controller_);
assistant_mini_view_->set_delegate(assistant_controller_->ui_controller());
assistant_mini_view_->set_owned_by_client();
AddChildView(assistant_mini_view_);
// Web view.
assistant_web_view_ =
std::make_unique<AssistantWebView>(assistant_controller_);
assistant_web_view_->set_owned_by_client();
assistant_web_view_ = new AssistantWebView(assistant_controller_);
AddChildView(assistant_web_view_);
// Update the view state based on the current UI mode.
OnUiModeChanged(assistant_controller_->ui_controller()->model()->ui_mode());
......@@ -135,17 +207,19 @@ void AssistantContainerView::SetAnchor() {
}
void AssistantContainerView::OnUiModeChanged(AssistantUiMode ui_mode) {
RemoveAllChildViews(/*delete_children=*/false);
for (int i = 0; i < child_count(); ++i) {
child_at(i)->SetVisible(false);
}
switch (ui_mode) {
case AssistantUiMode::kMiniUi:
AddChildView(assistant_mini_view_.get());
assistant_mini_view_->SetVisible(true);
break;
case AssistantUiMode::kMainUi:
AddChildView(assistant_main_view_.get());
assistant_main_view_->SetVisible(true);
break;
case AssistantUiMode::kWebUi:
AddChildView(assistant_web_view_.get());
assistant_web_view_->SetVisible(true);
break;
}
......
......@@ -5,8 +5,6 @@
#ifndef ASH_ASSISTANT_UI_ASSISTANT_CONTAINER_VIEW_H_
#define ASH_ASSISTANT_UI_ASSISTANT_CONTAINER_VIEW_H_
#include <memory>
#include "ash/assistant/model/assistant_ui_model_observer.h"
#include "base/macros.h"
#include "ui/views/bubble/bubble_dialog_delegate.h"
......@@ -42,9 +40,9 @@ class AssistantContainerView : public views::BubbleDialogDelegateView,
AssistantController* const assistant_controller_; // Owned by Shell.
std::unique_ptr<AssistantMainView> assistant_main_view_;
std::unique_ptr<AssistantMiniView> assistant_mini_view_;
std::unique_ptr<AssistantWebView> assistant_web_view_;
AssistantMainView* assistant_main_view_; // Owned by view hierarchy.
AssistantMiniView* assistant_mini_view_; // Owned by view hierarchy.
AssistantWebView* assistant_web_view_; // Owned by view hierarchy.
DISALLOW_COPY_AND_ASSIGN(AssistantContainerView);
};
......
......@@ -65,11 +65,15 @@ AssistantMainView::~AssistantMainView() {
}
gfx::Size AssistantMainView::CalculatePreferredSize() const {
// |min_height_dip_| <= |preferred_height| <= |kMaxHeightDip|.
int preferred_height = GetHeightForWidth(kPreferredWidthDip);
preferred_height = std::min(preferred_height, kMaxHeightDip);
preferred_height = std::max(preferred_height, min_height_dip_);
return gfx::Size(kPreferredWidthDip, preferred_height);
return gfx::Size(kPreferredWidthDip, GetHeightForWidth(kPreferredWidthDip));
}
int AssistantMainView::GetHeightForWidth(int width) const {
// |min_height_dip_| <= |height| <= |kMaxHeightDip|.
int height = views::View::GetHeightForWidth(width);
height = std::min(height, kMaxHeightDip);
height = std::max(height, min_height_dip_);
return height;
}
void AssistantMainView::OnBoundsChanged(const gfx::Rect& prev_bounds) {
......
......@@ -23,6 +23,7 @@ class AssistantMainView : public views::View, public AssistantUiModelObserver {
// views::View:
gfx::Size CalculatePreferredSize() const override;
int GetHeightForWidth(int width) const override;
void ChildPreferredSizeChanged(views::View* child) override;
void ChildVisibilityChanged(views::View* child) override;
void OnBoundsChanged(const gfx::Rect& prev_bounds) override;
......
......@@ -8,6 +8,8 @@
#include "ash/assistant/assistant_controller.h"
#include "ash/assistant/assistant_interaction_controller.h"
#include "ash/assistant/assistant_ui_controller.h"
#include "ash/assistant/model/assistant_query.h"
#include "ash/assistant/ui/assistant_ui_constants.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/strings/grit/ash_strings.h"
......@@ -41,9 +43,11 @@ AssistantMiniView::AssistantMiniView(AssistantController* assistant_controller)
// AssistantController indirectly owns the view hierarchy to which
// AssistantMiniView belongs so is guaranteed to outlive it.
assistant_controller_->interaction_controller()->AddModelObserver(this);
assistant_controller_->ui_controller()->AddModelObserver(this);
}
AssistantMiniView::~AssistantMiniView() {
assistant_controller_->ui_controller()->RemoveModelObserver(this);
assistant_controller_->interaction_controller()->RemoveModelObserver(this);
}
......@@ -87,10 +91,8 @@ void AssistantMiniView::InitLayout() {
label_->SetLineHeight(kLineHeightDip);
AddChildView(label_);
// Trigger input modality changed event to initialize view state.
OnInputModalityChanged(assistant_controller_->interaction_controller()
->model()
->input_modality());
// Initialize the prompt.
UpdatePrompt();
}
void AssistantMiniView::ButtonPressed(views::Button* sender,
......@@ -100,6 +102,55 @@ void AssistantMiniView::ButtonPressed(views::Button* sender,
}
void AssistantMiniView::OnInputModalityChanged(InputModality input_modality) {
UpdatePrompt();
}
void AssistantMiniView::OnResponseChanged(const AssistantResponse& response) {
// When a response changes, the committed query becomes active. We'll cache
// the text for that query to use as our prompt when not using the stylus.
const AssistantQuery& committed_query =
assistant_controller_->interaction_controller()
->model()
->committed_query();
switch (committed_query.type()) {
case AssistantQueryType::kText: {
const AssistantTextQuery& text_query =
static_cast<const AssistantTextQuery&>(committed_query);
last_active_query_ = text_query.text();
break;
}
case AssistantQueryType::kVoice: {
const AssistantVoiceQuery& voice_query =
static_cast<const AssistantVoiceQuery&>(committed_query);
last_active_query_ = voice_query.high_confidence_speech() +
voice_query.low_confidence_speech();
break;
}
case AssistantQueryType::kEmpty:
// It shouldn't be possible to commit a query of type kEmpty.
NOTREACHED();
break;
}
UpdatePrompt();
}
void AssistantMiniView::OnUiVisibilityChanged(bool visible,
AssistantSource source) {
if (visible)
return;
// Reset state for the next Assistant UI session.
last_active_query_.reset();
UpdatePrompt();
}
void AssistantMiniView::UpdatePrompt() {
InputModality input_modality = assistant_controller_->interaction_controller()
->model()
->input_modality();
switch (input_modality) {
case InputModality::kStylus:
label_->SetText(
......@@ -107,8 +158,12 @@ void AssistantMiniView::OnInputModalityChanged(InputModality input_modality) {
break;
case InputModality::kKeyboard:
case InputModality::kVoice:
// If we've cached an active query, we'll use that as our prompt. If not,
// we fall back to our default prompt string.
label_->SetText(
l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_PROMPT_DEFAULT));
last_active_query_.has_value()
? base::UTF8ToUTF16(last_active_query_.value())
: l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_PROMPT_DEFAULT));
break;
}
}
......
......@@ -5,8 +5,12 @@
#ifndef ASH_ASSISTANT_UI_ASSISTANT_MINI_VIEW_H_
#define ASH_ASSISTANT_UI_ASSISTANT_MINI_VIEW_H_
#include <string>
#include "ash/assistant/model/assistant_interaction_model_observer.h"
#include "ash/assistant/model/assistant_ui_model_observer.h"
#include "base/macros.h"
#include "base/optional.h"
#include "ui/views/controls/button/button.h"
namespace views {
......@@ -32,7 +36,8 @@ class AssistantMiniViewDelegate {
class AssistantMiniView : public views::Button,
public views::ButtonListener,
public AssistantInteractionModelObserver {
public AssistantInteractionModelObserver,
public AssistantUiModelObserver {
public:
explicit AssistantMiniView(AssistantController* assistant_controller);
~AssistantMiniView() override;
......@@ -47,6 +52,10 @@ class AssistantMiniView : public views::Button,
// AssistantInteractionModelObserver:
void OnInputModalityChanged(InputModality input_modality) override;
void OnResponseChanged(const AssistantResponse& response) override;
// AssistantUiModelObserver:
void OnUiVisibilityChanged(bool visible, AssistantSource source) override;
void set_delegate(AssistantMiniViewDelegate* delegate) {
delegate_ = delegate;
......@@ -54,12 +63,17 @@ class AssistantMiniView : public views::Button,
private:
void InitLayout();
void UpdatePrompt();
AssistantController* const assistant_controller_; // Owned by Shell.
views::Label* label_; // Owned by view hierarchy.
AssistantMiniViewDelegate* delegate_ = nullptr;
// The most recent active query for the current Assistant UI session. If there
// has been no active query for the current UI session, this is empty.
base::Optional<std::string> last_active_query_;
DISALLOW_COPY_AND_ASSIGN(AssistantMiniView);
};
......
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