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() { ...@@ -108,6 +108,7 @@ void QuickAnswersUiController::CloseUserConsentView() {
} }
void QuickAnswersUiController::OnConsentGrantedButtonPressed() { void QuickAnswersUiController::OnConsentGrantedButtonPressed() {
DCHECK(user_consent_view_);
controller_->OnUserConsentGranted(); controller_->OnUserConsentGranted();
} }
...@@ -116,6 +117,11 @@ void QuickAnswersUiController::OnManageSettingsButtonPressed() { ...@@ -116,6 +117,11 @@ void QuickAnswersUiController::OnManageSettingsButtonPressed() {
} }
void QuickAnswersUiController::OnDogfoodButtonPressed() { 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(); controller_->OpenQuickAnswersDogfoodLink();
} }
......
...@@ -5,26 +5,39 @@ ...@@ -5,26 +5,39 @@
#include "ash/quick_answers/ui/quick_answers_pre_target_handler.h" #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/quick_answers_view.h"
#include "ash/quick_answers/ui/user_consent_view.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/containers/adapters.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/tooltip_manager.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
namespace ash { namespace ash {
QuickAnswersPreTargetHandler::QuickAnswersPreTargetHandler( QuickAnswersPreTargetHandler::QuickAnswersPreTargetHandler(
QuickAnswersView* quick_answers_view) QuickAnswersView* view)
: quick_answers_view_(quick_answers_view) { : view_(view) {
// QuickAnswersView is a companion view of a menu. Menu host widget sets Init();
// 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); QuickAnswersPreTargetHandler::QuickAnswersPreTargetHandler(
quick_answers::UserConsentView* view)
: view_(view) {
Init();
} }
QuickAnswersPreTargetHandler::~QuickAnswersPreTargetHandler() { QuickAnswersPreTargetHandler::~QuickAnswersPreTargetHandler() {
Shell::Get()->RemovePreTargetHandler(this); 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) { void QuickAnswersPreTargetHandler::OnEvent(ui::Event* event) {
if (!event->IsLocatedEvent()) if (!event->IsLocatedEvent())
return; return;
...@@ -37,14 +50,13 @@ void QuickAnswersPreTargetHandler::OnEvent(ui::Event* event) { ...@@ -37,14 +50,13 @@ void QuickAnswersPreTargetHandler::OnEvent(ui::Event* event) {
// `ET_MOUSE_MOVED` events outside the top-view's bounds are also dispatched // `ET_MOUSE_MOVED` events outside the top-view's bounds are also dispatched
// to clear any set hover-state. // to clear any set hover-state.
bool dispatch_event = bool dispatch_event = (view_->GetBoundsInScreen().Contains(location) ||
(quick_answers_view_->GetBoundsInScreen().Contains(location) || to_dispatch->type() == ui::EventType::ET_MOUSE_MOVED);
to_dispatch->type() == ui::EventType::ET_MOUSE_MOVED);
if (dispatch_event) { if (dispatch_event) {
// Convert to local coordinates and forward to the top-view. // 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); 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 // Convert touch-event to gesture before dispatching since views do not
// process touch-events. // process touch-events.
...@@ -56,21 +68,36 @@ void QuickAnswersPreTargetHandler::OnEvent(ui::Event* event) { ...@@ -56,21 +68,36 @@ void QuickAnswersPreTargetHandler::OnEvent(ui::Event* event) {
to_dispatch = gesture_event.get(); to_dispatch = gesture_event.get();
} }
DoDispatchEvent(quick_answers_view_, to_dispatch); DoDispatchEvent(view_, to_dispatch);
// Clicks outside menu-bounds (including those inside QuickAnswersView) // Clicks inside Quick-Answers views can dismiss the menu since they are
// can dismiss the menu. Some click-events, like those meant for the // outside menu-bounds and are thus not propagated to it to prevent so.
// retry-button, should not be propagated to the menu to prevent so. // Active menu instance will instead be cancelled when |view_| is deleted.
if (quick_answers_view_->preempt_last_click_event()) if (event->type() != ui::ET_MOUSE_MOVED)
event->StopPropagation(); event->StopPropagation();
} }
// Show tooltips. // Show tooltips.
auto* tooltip_manager = quick_answers_view_->GetWidget()->GetTooltipManager(); auto* tooltip_manager = view_->GetWidget()->GetTooltipManager();
if (tooltip_manager) if (tooltip_manager)
tooltip_manager->UpdateTooltip(); 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, bool QuickAnswersPreTargetHandler::DoDispatchEvent(views::View* view,
ui::LocatedEvent* event) { ui::LocatedEvent* event) {
DCHECK(view && event); DCHECK(view && event);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define ASH_QUICK_ANSWERS_UI_QUICK_ANSWERS_PRE_TARGET_HANDLER_H_ #define ASH_QUICK_ANSWERS_UI_QUICK_ANSWERS_PRE_TARGET_HANDLER_H_
#include "ui/events/event_handler.h" #include "ui/events/event_handler.h"
#include "ui/views/view_observer.h"
namespace ui { namespace ui {
class LocatedEvent; class LocatedEvent;
...@@ -19,12 +20,18 @@ namespace ash { ...@@ -19,12 +20,18 @@ namespace ash {
class QuickAnswersView; class QuickAnswersView;
namespace quick_answers {
class UserConsentView;
} // namespace quick_answers
// This class handles mouse events, and update background color or // This class handles mouse events, and update background color or
// dismiss quick answers view. // dismiss quick answers view.
// TODO (siabhijeet): Migrate to using two-phased event dispatching. // TODO (siabhijeet): Migrate to using two-phased event dispatching.
class QuickAnswersPreTargetHandler : public ui::EventHandler { class QuickAnswersPreTargetHandler : public ui::EventHandler,
public views::ViewObserver {
public: public:
explicit QuickAnswersPreTargetHandler(QuickAnswersView* quick_answers_view); explicit QuickAnswersPreTargetHandler(QuickAnswersView* view);
explicit QuickAnswersPreTargetHandler(quick_answers::UserConsentView* view);
// Disallow copy and assign. // Disallow copy and assign.
QuickAnswersPreTargetHandler(const QuickAnswersPreTargetHandler&) = delete; QuickAnswersPreTargetHandler(const QuickAnswersPreTargetHandler&) = delete;
...@@ -36,11 +43,25 @@ class QuickAnswersPreTargetHandler : public ui::EventHandler { ...@@ -36,11 +43,25 @@ class QuickAnswersPreTargetHandler : public ui::EventHandler {
// ui::EventHandler: // ui::EventHandler:
void OnEvent(ui::Event* event) override; 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: private:
void Init();
// Returns true if event was consumed by |view| or its children. // Returns true if event was consumed by |view| or its children.
bool DoDispatchEvent(views::View* view, ui::LocatedEvent* event); 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 } // namespace ash
......
...@@ -166,14 +166,12 @@ void QuickAnswersView::StateChanged(views::Button::ButtonState old_state) { ...@@ -166,14 +166,12 @@ void QuickAnswersView::StateChanged(views::Button::ButtonState old_state) {
void QuickAnswersView::ButtonPressed(views::Button* sender, void QuickAnswersView::ButtonPressed(views::Button* sender,
const ui::Event& event) { const ui::Event& event) {
preempt_last_click_event_ = false;
if (sender == dogfood_button_) { if (sender == dogfood_button_) {
controller_->OnDogfoodButtonPressed(); controller_->OnDogfoodButtonPressed();
return; return;
} }
if (sender == retry_label_) { if (sender == retry_label_) {
controller_->OnRetryLabelPressed(); controller_->OnRetryLabelPressed();
preempt_last_click_event_ = true;
return; return;
} }
if (sender == this) { if (sender == this) {
......
...@@ -60,8 +60,6 @@ class ASH_EXPORT QuickAnswersView : public views::Button, ...@@ -60,8 +60,6 @@ class ASH_EXPORT QuickAnswersView : public views::Button,
void ShowRetryView(); void ShowRetryView();
bool preempt_last_click_event() const { return preempt_last_click_event_; }
private: private:
void InitLayout(); void InitLayout();
void InitWidget(); void InitWidget();
...@@ -79,7 +77,6 @@ class ASH_EXPORT QuickAnswersView : public views::Button, ...@@ -79,7 +77,6 @@ class ASH_EXPORT QuickAnswersView : public views::Button,
gfx::Rect anchor_view_bounds_; gfx::Rect anchor_view_bounds_;
QuickAnswersUiController* const controller_; QuickAnswersUiController* const controller_;
bool has_second_row_answer_ = false; bool has_second_row_answer_ = false;
bool preempt_last_click_event_ = false;
std::string title_; std::string title_;
views::View* main_view_ = nullptr; views::View* main_view_ = nullptr;
views::View* content_view_ = nullptr; views::View* content_view_ = nullptr;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "ash/public/cpp/vector_icons/vector_icons.h" #include "ash/public/cpp/vector_icons/vector_icons.h"
#include "ash/quick_answers/quick_answers_ui_controller.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/resources/vector_icons/vector_icons.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h" #include "ash/strings/grit/ash_strings.h"
...@@ -111,71 +112,12 @@ class CustomizedLabelButton : public views::LabelButton { ...@@ -111,71 +112,12 @@ class CustomizedLabelButton : public views::LabelButton {
} // namespace } // 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::UserConsentView(const gfx::Rect& anchor_view_bounds, UserConsentView::UserConsentView(const gfx::Rect& anchor_view_bounds,
QuickAnswersUiController* ui_controller) QuickAnswersUiController* ui_controller)
: anchor_view_bounds_(anchor_view_bounds), : anchor_view_bounds_(anchor_view_bounds),
event_handler_(std::make_unique<UserConsentViewPreTargetHandler>(this)), event_handler_(std::make_unique<QuickAnswersPreTargetHandler>(this)),
ui_controller_(ui_controller) { ui_controller_(ui_controller) {
InitLayout(); InitLayout();
InitWidget(); InitWidget();
...@@ -201,6 +143,9 @@ gfx::Size UserConsentView::CalculatePreferredSize() const { ...@@ -201,6 +143,9 @@ gfx::Size UserConsentView::CalculatePreferredSize() const {
void UserConsentView::ButtonPressed(views::Button* sender, void UserConsentView::ButtonPressed(views::Button* sender,
const ui::Event& event) { const ui::Event& event) {
if (sender == consent_button_) { 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(); ui_controller_->OnConsentGrantedButtonPressed();
return; return;
} }
......
...@@ -18,6 +18,7 @@ class LabelButton; ...@@ -18,6 +18,7 @@ class LabelButton;
namespace ash { namespace ash {
class QuickAnswersUiController; class QuickAnswersUiController;
class QuickAnswersPreTargetHandler;
namespace quick_answers { namespace quick_answers {
...@@ -54,7 +55,7 @@ class UserConsentView : public views::View, public views::ButtonListener { ...@@ -54,7 +55,7 @@ class UserConsentView : public views::View, public views::ButtonListener {
// Cached bounds of the anchor this view is tied to. // Cached bounds of the anchor this view is tied to.
gfx::Rect anchor_view_bounds_; gfx::Rect anchor_view_bounds_;
std::unique_ptr<EventHandler> event_handler_; std::unique_ptr<QuickAnswersPreTargetHandler> event_handler_;
QuickAnswersUiController* const ui_controller_; QuickAnswersUiController* const ui_controller_;
// Owned by view hierarchy. // 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