Commit a8cdf5a0 authored by Abhijeet Singh's avatar Abhijeet Singh Committed by Commit Bot

Make UserConsentView share logic from QuickAnswersPreTargetHandler

This CL makes quick_answers::UserConsentView share logic with
QuickAnswersView via a common pre-target handler. This change also
proposes handling context-menu, Quick Answers views are companion-views
of which, in a more robust way by dismissing it whenever these views are
closed.

Corner-case scenario where the menu should not be dismissed (for
example, QuickAnswersView should be displayed after acknowledging and
dismissing UserConsentView) is handled by the pre-target handler providing
a setter.

Bug: b:151111996
Test: Tested on Atlas test device.
Change-Id: I94fc256ca329787188315df8e71457e4530f4281
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2195338Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Abhijeet Singh <siabhijeet@google.com>
Cr-Commit-Position: refs/heads/master@{#768505}
parent 08aba6fc
......@@ -108,6 +108,7 @@ void QuickAnswersUiController::CloseUserConsentView() {
}
void QuickAnswersUiController::OnConsentGrantedButtonPressed() {
DCHECK(user_consent_view_);
controller_->OnUserConsentGranted();
}
......@@ -116,6 +117,11 @@ void QuickAnswersUiController::OnManageSettingsButtonPressed() {
}
void QuickAnswersUiController::OnDogfoodButtonPressed() {
// Close Quick-Answers related views and open the Dogfood link.
if (quick_answers_view_)
CloseQuickAnswersView();
if (user_consent_view_)
CloseUserConsentView();
controller_->OpenQuickAnswersDogfoodLink();
}
......
......@@ -5,26 +5,39 @@
#include "ash/quick_answers/ui/quick_answers_pre_target_handler.h"
#include "ash/quick_answers/ui/quick_answers_view.h"
#include "ash/quick_answers/ui/user_consent_view.h"
#include "ash/shell.h"
#include "base/containers/adapters.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/widget/tooltip_manager.h"
#include "ui/views/widget/widget.h"
namespace ash {
QuickAnswersPreTargetHandler::QuickAnswersPreTargetHandler(
QuickAnswersView* quick_answers_view)
: quick_answers_view_(quick_answers_view) {
// QuickAnswersView is a companion view of a menu. Menu host widget sets
// mouse capture as well as a pre-target handler, so we need to register one
// here as well to intercept events for QuickAnswersView.
Shell::Get()->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
QuickAnswersView* view)
: view_(view) {
Init();
}
QuickAnswersPreTargetHandler::QuickAnswersPreTargetHandler(
quick_answers::UserConsentView* view)
: view_(view) {
Init();
}
QuickAnswersPreTargetHandler::~QuickAnswersPreTargetHandler() {
Shell::Get()->RemovePreTargetHandler(this);
}
void QuickAnswersPreTargetHandler::Init() {
// QuickAnswersView is a companion view of a menu. Menu host widget sets
// mouse capture as well as a pre-target handler, so we need to register one
// here as well to intercept events for QuickAnswersView.
Shell::Get()->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
view_->AddObserver(this);
}
void QuickAnswersPreTargetHandler::OnEvent(ui::Event* event) {
if (!event->IsLocatedEvent())
return;
......@@ -37,14 +50,13 @@ void QuickAnswersPreTargetHandler::OnEvent(ui::Event* event) {
// `ET_MOUSE_MOVED` events outside the top-view's bounds are also dispatched
// to clear any set hover-state.
bool dispatch_event =
(quick_answers_view_->GetBoundsInScreen().Contains(location) ||
to_dispatch->type() == ui::EventType::ET_MOUSE_MOVED);
bool dispatch_event = (view_->GetBoundsInScreen().Contains(location) ||
to_dispatch->type() == ui::EventType::ET_MOUSE_MOVED);
if (dispatch_event) {
// Convert to local coordinates and forward to the top-view.
views::View::ConvertPointFromScreen(quick_answers_view_, &location);
views::View::ConvertPointFromScreen(view_, &location);
to_dispatch->set_location(location);
ui::Event::DispatcherApi(to_dispatch).set_target(quick_answers_view_);
ui::Event::DispatcherApi(to_dispatch).set_target(view_);
// Convert touch-event to gesture before dispatching since views do not
// process touch-events.
......@@ -56,21 +68,36 @@ void QuickAnswersPreTargetHandler::OnEvent(ui::Event* event) {
to_dispatch = gesture_event.get();
}
DoDispatchEvent(quick_answers_view_, to_dispatch);
DoDispatchEvent(view_, to_dispatch);
// Clicks outside menu-bounds (including those inside QuickAnswersView)
// can dismiss the menu. Some click-events, like those meant for the
// retry-button, should not be propagated to the menu to prevent so.
if (quick_answers_view_->preempt_last_click_event())
// Clicks inside Quick-Answers views can dismiss the menu since they are
// outside menu-bounds and are thus not propagated to it to prevent so.
// Active menu instance will instead be cancelled when |view_| is deleted.
if (event->type() != ui::ET_MOUSE_MOVED)
event->StopPropagation();
}
// Show tooltips.
auto* tooltip_manager = quick_answers_view_->GetWidget()->GetTooltipManager();
auto* tooltip_manager = view_->GetWidget()->GetTooltipManager();
if (tooltip_manager)
tooltip_manager->UpdateTooltip();
}
void QuickAnswersPreTargetHandler::OnViewIsDeleting(
views::View* observed_view) {
DCHECK_EQ(observed_view, view_);
// Cancel any active context-menus, the deleting Quick-Answers view is a
// companion-view of which, unless it requests otherwise for some cases.
if (dismiss_anchor_menu_on_view_closed_) {
auto* active_menu_instance = views::MenuController::GetActiveInstance();
if (active_menu_instance)
active_menu_instance->Cancel(views::MenuController::ExitType::kAll);
}
view_->RemoveObserver(this);
}
// TODO(siabhijeet): Investigate using SendEventsToSink() for dispatching.
bool QuickAnswersPreTargetHandler::DoDispatchEvent(views::View* view,
ui::LocatedEvent* event) {
DCHECK(view && event);
......
......@@ -6,6 +6,7 @@
#define ASH_QUICK_ANSWERS_UI_QUICK_ANSWERS_PRE_TARGET_HANDLER_H_
#include "ui/events/event_handler.h"
#include "ui/views/view_observer.h"
namespace ui {
class LocatedEvent;
......@@ -19,12 +20,18 @@ namespace ash {
class QuickAnswersView;
namespace quick_answers {
class UserConsentView;
} // namespace quick_answers
// This class handles mouse events, and update background color or
// dismiss quick answers view.
// TODO (siabhijeet): Migrate to using two-phased event dispatching.
class QuickAnswersPreTargetHandler : public ui::EventHandler {
class QuickAnswersPreTargetHandler : public ui::EventHandler,
public views::ViewObserver {
public:
explicit QuickAnswersPreTargetHandler(QuickAnswersView* quick_answers_view);
explicit QuickAnswersPreTargetHandler(QuickAnswersView* view);
explicit QuickAnswersPreTargetHandler(quick_answers::UserConsentView* view);
// Disallow copy and assign.
QuickAnswersPreTargetHandler(const QuickAnswersPreTargetHandler&) = delete;
......@@ -36,11 +43,25 @@ class QuickAnswersPreTargetHandler : public ui::EventHandler {
// ui::EventHandler:
void OnEvent(ui::Event* event) override;
// views::ViewObserver:
void OnViewIsDeleting(views::View* observed_view) override;
void set_dismiss_anchor_menu_on_view_closed(bool dismiss) {
dismiss_anchor_menu_on_view_closed_ = dismiss;
}
private:
void Init();
// Returns true if event was consumed by |view| or its children.
bool DoDispatchEvent(views::View* view, ui::LocatedEvent* event);
QuickAnswersView* quick_answers_view_;
// Associated view handled by this class.
views::View* const view_;
// Whether any active menus, |view_| is a companion Quick-Answers related view
// of which, should be dismissed when it is deleted.
bool dismiss_anchor_menu_on_view_closed_ = true;
};
} // namespace ash
......
......@@ -166,14 +166,12 @@ void QuickAnswersView::StateChanged(views::Button::ButtonState old_state) {
void QuickAnswersView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
preempt_last_click_event_ = false;
if (sender == dogfood_button_) {
controller_->OnDogfoodButtonPressed();
return;
}
if (sender == retry_label_) {
controller_->OnRetryLabelPressed();
preempt_last_click_event_ = true;
return;
}
if (sender == this) {
......
......@@ -60,8 +60,6 @@ class ASH_EXPORT QuickAnswersView : public views::Button,
void ShowRetryView();
bool preempt_last_click_event() const { return preempt_last_click_event_; }
private:
void InitLayout();
void InitWidget();
......@@ -79,7 +77,6 @@ class ASH_EXPORT QuickAnswersView : public views::Button,
gfx::Rect anchor_view_bounds_;
QuickAnswersUiController* const controller_;
bool has_second_row_answer_ = false;
bool preempt_last_click_event_ = false;
std::string title_;
views::View* main_view_ = nullptr;
views::View* content_view_ = nullptr;
......
......@@ -6,6 +6,7 @@
#include "ash/public/cpp/vector_icons/vector_icons.h"
#include "ash/quick_answers/quick_answers_ui_controller.h"
#include "ash/quick_answers/ui/quick_answers_pre_target_handler.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
......@@ -111,71 +112,12 @@ class CustomizedLabelButton : public views::LabelButton {
} // namespace
// UserConsentViewPreTargetHandler ---------------------------------------------
// TODO(siabhijeet): Reuse pre-target handler for QuickAnswersView.
class UserConsentViewPreTargetHandler : public ui::EventHandler {
public:
explicit UserConsentViewPreTargetHandler(UserConsentView* view)
: view_(view) {
Shell::Get()->AddPreTargetHandler(this);
}
~UserConsentViewPreTargetHandler() override {
Shell::Get()->RemovePreTargetHandler(this);
}
UserConsentViewPreTargetHandler(const UserConsentViewPreTargetHandler&) =
delete;
UserConsentViewPreTargetHandler& operator=(
const UserConsentViewPreTargetHandler&) = delete;
// ui::EventHandler:
void OnEvent(ui::Event* event) override {
if (!event->IsLocatedEvent())
return;
auto* located_event = event->AsLocatedEvent();
auto location = located_event->target()->GetScreenLocation(*located_event);
if (view_->GetBoundsInScreen().Contains(location)) {
DoDispatchEvent(view_, located_event);
event->StopPropagation();
auto* tooltip_manager = view_->GetWidget()->GetTooltipManager();
if (tooltip_manager)
tooltip_manager->UpdateTooltip();
}
}
private:
// TODO(siabhijeet): Investigate using SendEventsToSink() instead.
bool DoDispatchEvent(views::View* view, ui::LocatedEvent* event) {
if (event->handled())
return true;
// Convert |event| to local coordinates of |view|.
gfx::Point location = event->target()->GetScreenLocation(*event);
views::View::ConvertPointFromScreen(view, &location);
event->set_location(location);
ui::Event::DispatcherApi(event).set_target(view);
// Process event and dispatch on children recursively.
view->OnEvent(event);
for (auto* child : view->children()) {
if (DoDispatchEvent(child, event))
return true;
}
return false;
}
// Associated view handled by this class.
UserConsentView* const view_;
};
// UserConsentView -------------------------------------------------------------
UserConsentView::UserConsentView(const gfx::Rect& anchor_view_bounds,
QuickAnswersUiController* ui_controller)
: anchor_view_bounds_(anchor_view_bounds),
event_handler_(std::make_unique<UserConsentViewPreTargetHandler>(this)),
event_handler_(std::make_unique<QuickAnswersPreTargetHandler>(this)),
ui_controller_(ui_controller) {
InitLayout();
InitWidget();
......@@ -201,6 +143,9 @@ gfx::Size UserConsentView::CalculatePreferredSize() const {
void UserConsentView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender == consent_button_) {
// When user-consent is acknowledged, QuickAnswersView will be displayed
// instead of dismissing the menu.
event_handler_->set_dismiss_anchor_menu_on_view_closed(false);
ui_controller_->OnConsentGrantedButtonPressed();
return;
}
......
......@@ -18,6 +18,7 @@ class LabelButton;
namespace ash {
class QuickAnswersUiController;
class QuickAnswersPreTargetHandler;
namespace quick_answers {
......@@ -54,7 +55,7 @@ class UserConsentView : public views::View, public views::ButtonListener {
// Cached bounds of the anchor this view is tied to.
gfx::Rect anchor_view_bounds_;
std::unique_ptr<EventHandler> event_handler_;
std::unique_ptr<QuickAnswersPreTargetHandler> event_handler_;
QuickAnswersUiController* const ui_controller_;
// Owned by view hierarchy.
......
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