Commit a061f174 authored by Weidong Guo's avatar Weidong Guo Committed by Commit Bot

Fix browser with print dialog animation issue

Background:
When dragging home launcher down to show a window, the window will be
shown on drag start and will slide down on drag update. However, this
does not work for window with modal dialog because the dialog's
visibility change cancels the touches for all other windows.

Changes:
Avoid cancel touches on windows that are not in the same transient
window tree of the modal dialog.

Bug: 900321
Change-Id: I2047224de2f6fac9e892376477b7bf9c938cc2c0
Reviewed-on: https://chromium-review.googlesource.com/c/1316434
Commit-Queue: Weidong Guo <weidongg@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607883}
parent 8d41f8c9
......@@ -405,45 +405,127 @@ class TouchTrackerWindowDelegate : public aura::test::TestWindowDelegate {
DISALLOW_COPY_AND_ASSIGN(TouchTrackerWindowDelegate);
};
// Modality should prevent events from being passed to the transient parent.
// Modality should prevent events from being passed to transient window tree
// rooted to the top level window.
TEST_F(WindowModalityControllerTest, TouchEvent) {
TouchTrackerWindowDelegate d1;
std::unique_ptr<aura::Window> w1(
CreateTestWindowInShellWithDelegate(&d1, -1, gfx::Rect(0, 0, 100, 100)));
TouchTrackerWindowDelegate d11;
std::unique_ptr<aura::Window> w11(CreateTestWindowInShellWithDelegate(
&d11, -11, gfx::Rect(20, 20, 50, 50)));
// Make |w11| non-resizable to avoid touch events inside its transient parent
// |w1| from going to |w11| because of EasyResizeWindowTargeter.
&d11, -11, gfx::Rect(20, 20, 20, 20)));
TouchTrackerWindowDelegate d12;
std::unique_ptr<aura::Window> w12(CreateTestWindowInShellWithDelegate(
&d12, -12, gfx::Rect(40, 20, 20, 20)));
TouchTrackerWindowDelegate d2;
std::unique_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate(
&d2, -2, gfx::Rect(100, 0, 100, 100)));
// Make |w11| and |w12| non-resizable to avoid touch events inside its
// transient parent |w1| from going to them because of
// EasyResizeWindowTargeter.
w11->SetProperty(aura::client::kResizeBehaviorKey,
ws::mojom::kResizeBehaviorCanMaximize |
ws::mojom::kResizeBehaviorCanMinimize);
w12->SetProperty(aura::client::kResizeBehaviorKey,
ws::mojom::kResizeBehaviorCanMaximize |
ws::mojom::kResizeBehaviorCanMinimize);
ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
gfx::Point(10, 10));
::wm::AddTransientChild(w1.get(), w11.get());
::wm::AddTransientChild(w1.get(), w12.get());
d1.reset();
d11.reset();
d12.reset();
d2.reset();
{
// Clicking a point within w1 should activate that window.
generator.PressMoveAndReleaseTouchTo(gfx::Point(10, 10));
// Adding a modal window while a touch is down in top level transient window
// should fire a touch cancel.
generator.PressTouch();
generator.MoveTouch(gfx::Point(10, 15));
EXPECT_TRUE(d1.received_touch());
EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
d1.reset();
d11.reset();
d12.reset();
d2.reset();
w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
EXPECT_TRUE(d1.received_touch());
EXPECT_EQ(ui::ET_TOUCH_CANCELLED, d1.last_event_type());
EXPECT_FALSE(d11.received_touch());
EXPECT_FALSE(d12.received_touch());
EXPECT_FALSE(d2.received_touch());
w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
}
{
// Adding a modal window while a touch is down should fire a touch cancel.
// Adding a modal window while a touch is down in window tree rooted to top
// level transient window should fire a touch cancel.
generator.MoveTouch(gfx::Point(50, 30));
generator.PressTouch();
generator.MoveTouch(gfx::Point(10, 10));
generator.MoveTouch(gfx::Point(50, 35));
EXPECT_TRUE(d12.received_touch());
EXPECT_TRUE(wm::IsActiveWindow(w12.get()));
d1.reset();
d11.reset();
d12.reset();
d2.reset();
w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
EXPECT_TRUE(d1.received_touch());
EXPECT_EQ(ui::ET_TOUCH_CANCELLED, d1.last_event_type());
EXPECT_FALSE(d1.received_touch());
EXPECT_FALSE(d11.received_touch());
EXPECT_TRUE(d12.received_touch());
EXPECT_EQ(ui::ET_TOUCH_CANCELLED, d12.last_event_type());
EXPECT_FALSE(d2.received_touch());
w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
}
{
// Adding a modal window while a touch is down in other transient window
// tree should not fire a touch cancel.
wm::ActivateWindow(w2.get());
generator.MoveTouch(gfx::Point(110, 10));
generator.PressTouch();
generator.MoveTouch(gfx::Point(110, 15));
EXPECT_TRUE(d2.received_touch());
EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
d1.reset();
d11.reset();
d12.reset();
d2.reset();
w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
EXPECT_FALSE(d1.received_touch());
EXPECT_FALSE(d11.received_touch());
EXPECT_FALSE(d12.received_touch());
EXPECT_FALSE(d2.received_touch());
w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
}
{
// Adding a child type modal window while a touch is down in other transient
// window tree should not fire a touch cancel. (See
// https://crbug.com/900321)
wm::ActivateWindow(w2.get());
generator.MoveTouch(gfx::Point(110, 10));
generator.PressTouch();
generator.MoveTouch(gfx::Point(110, 15));
EXPECT_TRUE(d2.received_touch());
EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
d1.reset();
d11.reset();
d12.reset();
d2.reset();
w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_CHILD);
EXPECT_FALSE(d1.received_touch());
EXPECT_FALSE(d11.received_touch());
EXPECT_FALSE(d12.received_touch());
EXPECT_FALSE(d2.received_touch());
w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
}
}
......
......@@ -54,13 +54,17 @@ class EVENTS_EXPORT GestureRecognizer {
// |source_device_id|, within
// GestureConfiguration::max_separation_for_gesture_touches_in_pixels of
// |location|, or NULL if no such point exists.
virtual GestureConsumer* GetTargetForLocation(
const gfx::PointF& location, int source_device_id) = 0;
virtual GestureConsumer* GetTargetForLocation(const gfx::PointF& location,
int source_device_id) = 0;
// Cancels all touches except those targeted to |not_cancelled|. If
// |not_cancelled| == nullptr, cancels all touches.
virtual void CancelActiveTouchesExcept(GestureConsumer* not_cancelled) = 0;
// Cancels all touches to the specified consumers.
virtual void CancelActiveTouchesOn(
const std::vector<GestureConsumer*>& consumers) = 0;
// Transfer the gesture stream from the drag source (current_consumer) to the
// consumer used for dragging (new_consumer). If |transfer_touches_behavior|
// is kCancel, dispatches cancel events to |current_consumer| to ensure that
......
......@@ -60,11 +60,9 @@ bool RemoveValueFromMap(std::map<Key, T>* map, const Value& value) {
////////////////////////////////////////////////////////////////////////////////
// GestureRecognizerImpl, public:
GestureRecognizerImpl::GestureRecognizerImpl() {
}
GestureRecognizerImpl::GestureRecognizerImpl() = default;
GestureRecognizerImpl::~GestureRecognizerImpl() {
}
GestureRecognizerImpl::~GestureRecognizerImpl() = default;
// Checks if this finger is already down, if so, returns the current target.
// Otherwise, returns NULL.
......@@ -74,7 +72,8 @@ GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
}
GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
const gfx::PointF& location, int source_device_id) {
const gfx::PointF& location,
int source_device_id) {
const float max_distance =
GestureConfiguration::GetInstance()
->max_separation_for_gesture_touches_in_pixels();
......@@ -111,6 +110,14 @@ void GestureRecognizerImpl::CancelActiveTouchesExcept(
CancelActiveTouchesExceptImpl(not_cancelled, kNotifyObservers);
}
void GestureRecognizerImpl::CancelActiveTouchesOn(
const std::vector<GestureConsumer*>& consumers) {
for (auto* consumer : consumers) {
if (base::ContainsKey(consumer_gesture_provider_, consumer))
CancelActiveTouchesImpl(consumer, kNotifyObservers);
}
}
void GestureRecognizerImpl::TransferEventsTo(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
......@@ -137,7 +144,7 @@ void GestureRecognizerImpl::TransferEventsTo(
std::vector<int> touchids_targeted_at_current;
for (const auto& touch_id_target: touch_id_target_) {
for (const auto& touch_id_target : touch_id_target_) {
if (touch_id_target.second == current_consumer)
touchids_targeted_at_current.push_back(touch_id_target.first);
}
......@@ -348,8 +355,7 @@ bool GestureRecognizerImpl::CancelActiveTouchesImpl(
return true;
}
bool GestureRecognizerImpl::CleanupStateForConsumer(
GestureConsumer* consumer) {
bool GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) {
bool state_cleaned_up = false;
state_cleaned_up |= RemoveValueFromMap(&touch_id_target_, consumer);
......
......@@ -48,6 +48,8 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer,
GestureConsumer* GetTargetForLocation(const gfx::PointF& location,
int source_device_id) override;
void CancelActiveTouchesExcept(GestureConsumer* not_cancelled) override;
void CancelActiveTouchesOn(
const std::vector<GestureConsumer*>& consumers) override;
void TransferEventsTo(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
......
......@@ -42,6 +42,9 @@ GestureConsumer* GestureRecognizerImplMac::GetTargetForLocation(
void GestureRecognizerImplMac::CancelActiveTouchesExcept(
GestureConsumer* not_cancelled) {}
void GestureRecognizerImplMac::CancelActiveTouchesOn(
const std::vector<GestureConsumer*>& consumers) {}
void GestureRecognizerImplMac::TransferEventsTo(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
......
......@@ -34,6 +34,8 @@ class EVENTS_EXPORT GestureRecognizerImplMac : public GestureRecognizer {
GestureConsumer* GetTargetForLocation(const gfx::PointF& location,
int source_device_id) override;
void CancelActiveTouchesExcept(GestureConsumer* not_cancelled) override;
void CancelActiveTouchesOn(
const std::vector<GestureConsumer*>& consumers) override;
void TransferEventsTo(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
......
......@@ -7,6 +7,7 @@
#include <stddef.h>
#include <algorithm>
#include <queue>
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/capture_client.h"
......@@ -52,9 +53,8 @@ bool IsModalTransientChild(aura::Window* transient, aura::Window* original) {
HasAncestor(original, GetModalParent(transient))));
}
aura::Window* GetModalTransientChild(
aura::Window* activatable,
aura::Window* original) {
aura::Window* GetModalTransientChild(aura::Window* activatable,
aura::Window* original) {
for (aura::Window* transient : GetTransientChildren(activatable)) {
if (IsModalTransientChild(transient, original)) {
if (GetTransientChildren(transient).empty())
......@@ -116,7 +116,7 @@ void WindowModalityController::OnKeyEvent(ui::KeyEvent* event) {
void WindowModalityController::OnMouseEvent(ui::MouseEvent* event) {
aura::Window* target = static_cast<aura::Window*>(event->target());
if (ProcessLocatedEvent(target, event))
event->SetHandled();
event->SetHandled();
}
void WindowModalityController::OnTouchEvent(ui::TouchEvent* event) {
......@@ -145,16 +145,16 @@ void WindowModalityController::OnWindowPropertyChanged(aura::Window* window,
window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE &&
window->IsVisible()) {
ActivateWindow(window);
env_->gesture_recognizer()->CancelActiveTouchesExcept(nullptr);
CancelTouchesOnTransientWindowTree(window);
}
}
void WindowModalityController::OnWindowVisibilityChanged(
aura::Window* window,
bool visible) {
void WindowModalityController::OnWindowVisibilityChanged(aura::Window* window,
bool visible) {
if (visible &&
window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) {
env_->gesture_recognizer()->CancelActiveTouchesExcept(nullptr);
CancelTouchesOnTransientWindowTree(window);
// Make sure no other window has capture, otherwise |window| won't get mouse
// events.
aura::Window* capture_window = aura::client::GetCaptureWindow(window);
......@@ -201,4 +201,28 @@ bool WindowModalityController::ProcessLocatedEvent(aura::Window* target,
return !!modal_transient_child;
}
void WindowModalityController::CancelTouchesOnTransientWindowTree(
aura::Window* window) {
// Find the top level transient window.
aura::Window* top_level_window = window;
while (wm::GetTransientParent(top_level_window))
top_level_window = wm::GetTransientParent(top_level_window);
// BFS to get all transient windows in the tree rooted to the top level
// transient window.
std::vector<ui::GestureConsumer*> blocked_consumers;
std::queue<aura::Window*> que;
que.emplace(top_level_window);
while (!que.empty()) {
aura::Window* parent = que.front();
que.pop();
blocked_consumers.emplace_back(parent);
for (auto* w : wm::GetTransientChildren(parent))
que.emplace(w);
}
// Cancel touches on all the transient windows.
env_->gesture_recognizer()->CancelActiveTouchesOn(blocked_consumers);
}
} // namespace wm
......@@ -21,7 +21,7 @@ class Env;
namespace ui {
class EventTarget;
class LocatedEvent;
}
} // namespace ui
namespace wm {
......@@ -61,8 +61,11 @@ class WM_CORE_EXPORT WindowModalityController : public ui::EventHandler,
private:
// Processes a mouse/touch event, and returns true if the event should be
// consumed.
bool ProcessLocatedEvent(aura::Window* target,
ui::LocatedEvent* event);
bool ProcessLocatedEvent(aura::Window* target, ui::LocatedEvent* event);
// Cancel touches on the transient window tree rooted to the top level
// transient window of the |window|.
void CancelTouchesOnTransientWindowTree(aura::Window* window);
aura::Env* env_;
......
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