summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authortdanderson@chromium.org <tdanderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-17 05:20:39 +0000
committertdanderson@chromium.org <tdanderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-17 05:20:39 +0000
commitb8642ec4593f6daf22cd4c70d422f5cc40c16e7f (patch)
tree5302bf7dabae2b993be22842843fe0d7d0112783 /ash
parentd7cf7264b7844ba136eeca7dfe82c806c1c46a9c (diff)
downloadchromium_src-b8642ec4593f6daf22cd4c70d422f5cc40c16e7f.zip
chromium_src-b8642ec4593f6daf22cd4c70d422f5cc40c16e7f.tar.gz
chromium_src-b8642ec4593f6daf22cd4c70d422f5cc40c16e7f.tar.bz2
Disallow touch hit-testing along attached edges of panels
Introduce AttachedPanelWindowTargeter, a new derived class of EasyResizeWindowTargeter. When installed as the EventTargeter of a panel container, the extended touch hit-testing inset is set to 0 for the edges of panels adjacent to the shelf. This makes it significantly easier to correctly target shelf buttons with touch because shelf-adjacent edges of panels are prevented from themselves being targets. BUG=351348 TEST=WorkspaceControllerTest.WindowEdgeTouchHitTestPanel,PanelLayoutManagerTest.TouchHitTestPanel Review URL: https://codereview.chromium.org/232703006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@264429 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/root_window_controller.cc19
-rw-r--r--ash/shell.cc6
-rw-r--r--ash/shell.h3
-rw-r--r--ash/shell_observer.h3
-rw-r--r--ash/wm/panels/attached_panel_window_targeter.cc75
-rw-r--r--ash/wm/panels/attached_panel_window_targeter.h43
-rw-r--r--ash/wm/panels/panel_layout_manager_unittest.cc77
-rw-r--r--ash/wm/workspace_controller_unittest.cc34
9 files changed, 256 insertions, 6 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 5b6350c..690605f 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -606,6 +606,8 @@
'wm/overview/window_selector_panels.h',
'wm/overview/window_selector_window.cc',
'wm/overview/window_selector_window.h',
+ 'wm/panels/attached_panel_window_targeter.cc',
+ 'wm/panels/attached_panel_window_targeter.h',
'wm/panels/panel_frame_view.cc',
'wm/panels/panel_frame_view.h',
'wm/panels/panel_layout_manager.cc',
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 3d4a839..6dd3b67 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -33,6 +33,7 @@
#include "ash/touch/touch_observer_hud.h"
#include "ash/wm/always_on_top_controller.h"
#include "ash/wm/dock/docked_window_layout_manager.h"
+#include "ash/wm/panels/attached_panel_window_targeter.h"
#include "ash/wm/panels/panel_layout_manager.h"
#include "ash/wm/panels/panel_window_event_handler.h"
#include "ash/wm/root_window_layout_manager.h"
@@ -415,6 +416,9 @@ void RootWindowController::OnShelfCreated() {
if (shelf_->shelf_layout_manager())
docked_layout_manager_->AddObserver(shelf_->shelf_layout_manager());
}
+
+ // Notify shell observers that the shelf has been created.
+ Shell::GetInstance()->OnShelfCreatedForRootWindow(GetRootWindow());
}
void RootWindowController::UpdateAfterLoginStatusChange(
@@ -785,6 +789,20 @@ void RootWindowController::InitLayoutManagers() {
panel_container->SetLayoutManager(panel_layout_manager_);
panel_container_handler_.reset(new PanelWindowEventHandler);
panel_container->AddPreTargetHandler(panel_container_handler_.get());
+
+ // Install an AttachedPanelWindowTargeter on the panel container to make it
+ // easier to correctly target shelf buttons with touch.
+ gfx::Insets mouse_extend(-kResizeOutsideBoundsSize,
+ -kResizeOutsideBoundsSize,
+ -kResizeOutsideBoundsSize,
+ -kResizeOutsideBoundsSize);
+ gfx::Insets touch_extend = mouse_extend.Scale(
+ kResizeOutsideBoundsScaleForTouch);
+ panel_container->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
+ new AttachedPanelWindowTargeter(panel_container,
+ mouse_extend,
+ touch_extend,
+ panel_layout_manager_)));
}
void RootWindowController::InitTouchHuds() {
@@ -894,7 +912,6 @@ void RootWindowController::CreateContainersInRootWindow(
"PanelContainer",
non_lock_screen_containers);
SetUsesScreenCoordinates(panel_container);
- SetUsesEasyResizeTargeter(panel_container);
aura::Window* shelf_bubble_container =
CreateContainer(kShellWindowId_ShelfBubbleContainer,
diff --git a/ash/shell.cc b/ash/shell.cc
index 2c0277f..e694630 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -407,6 +407,12 @@ void Shell::CreateShelf() {
(*iter)->shelf()->CreateShelf();
}
+void Shell::OnShelfCreatedForRootWindow(aura::Window* root_window) {
+ FOR_EACH_OBSERVER(ShellObserver,
+ observers_,
+ OnShelfCreatedForRootWindow(root_window));
+}
+
void Shell::CreateKeyboard() {
// TODO(bshe): Primary root window controller may not be the controller to
// attach virtual keyboard. See http://crbug.com/303429
diff --git a/ash/shell.h b/ash/shell.h
index 90746c8..6f88e1d 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -307,6 +307,9 @@ class ASH_EXPORT Shell : public SystemModalContainerEventFilterDelegate,
// Initializes |shelf_|. Does nothing if it's already initialized.
void CreateShelf();
+ // Called when the shelf is created for |root_window|.
+ void OnShelfCreatedForRootWindow(aura::Window* root_window);
+
// Creates a virtual keyboard. Deletes the old virtual keyboard if it already
// exists.
void CreateKeyboard();
diff --git a/ash/shell_observer.h b/ash/shell_observer.h
index 8c393d3..35b2555 100644
--- a/ash/shell_observer.h
+++ b/ash/shell_observer.h
@@ -32,6 +32,9 @@ class ASH_EXPORT ShellObserver {
// Invoked after a non-primary root window is created.
virtual void OnRootWindowAdded(aura::Window* root_window) {}
+ // Invoked after the shelf has been created for |root_window|.
+ virtual void OnShelfCreatedForRootWindow(aura::Window* root_window) {}
+
// Invoked when the shelf alignment in |root_window| is changed.
virtual void OnShelfAlignmentChanged(aura::Window* root_window) {}
diff --git a/ash/wm/panels/attached_panel_window_targeter.cc b/ash/wm/panels/attached_panel_window_targeter.cc
new file mode 100644
index 0000000..4e8b8f7
--- /dev/null
+++ b/ash/wm/panels/attached_panel_window_targeter.cc
@@ -0,0 +1,75 @@
+// Copyright 2014 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.
+
+#include "ash/wm/panels/attached_panel_window_targeter.h"
+
+#include "ash/shelf/shelf.h"
+#include "ash/shell.h"
+#include "ash/wm/panels/panel_layout_manager.h"
+
+namespace ash {
+
+AttachedPanelWindowTargeter::AttachedPanelWindowTargeter(
+ aura::Window* container,
+ const gfx::Insets& default_mouse_extend,
+ const gfx::Insets& default_touch_extend,
+ PanelLayoutManager* panel_layout_manager)
+ : ::wm::EasyResizeWindowTargeter(container,
+ default_mouse_extend,
+ default_touch_extend),
+ panel_container_(container),
+ panel_layout_manager_(panel_layout_manager),
+ default_touch_extend_(default_touch_extend) {
+ Shell::GetInstance()->AddShellObserver(this);
+}
+
+AttachedPanelWindowTargeter::~AttachedPanelWindowTargeter() {
+ Shell::GetInstance()->RemoveShellObserver(this);
+}
+
+void AttachedPanelWindowTargeter::OnShelfCreatedForRootWindow(
+ aura::Window* root_window) {
+ UpdateTouchExtend(root_window);
+}
+
+void AttachedPanelWindowTargeter::OnShelfAlignmentChanged(
+ aura::Window* root_window) {
+ // Don't update the touch insets if the shelf has not yet been created.
+ if (!panel_layout_manager_->shelf())
+ return;
+
+ UpdateTouchExtend(root_window);
+}
+
+void AttachedPanelWindowTargeter::UpdateTouchExtend(aura::Window* root_window) {
+ // Only update the touch insets for panels if they are attached to the shelf
+ // in |root_window|.
+ if (panel_container_->GetRootWindow() != root_window)
+ return;
+
+ DCHECK(panel_layout_manager_->shelf());
+
+ gfx::Insets touch(default_touch_extend_);
+ switch (panel_layout_manager_->shelf()->alignment()) {
+ case SHELF_ALIGNMENT_BOTTOM:
+ touch = gfx::Insets(touch.top(), touch.left(), 0, touch.right());
+ break;
+ case SHELF_ALIGNMENT_LEFT:
+ touch = gfx::Insets(touch.top(), 0, touch.bottom(), touch.right());
+ break;
+ case SHELF_ALIGNMENT_RIGHT:
+ touch = gfx::Insets(touch.top(), touch.left(), touch.bottom(), 0);
+ break;
+ case SHELF_ALIGNMENT_TOP:
+ touch = gfx::Insets(0, touch.left(), touch.bottom(), touch.right());
+ break;
+ default:
+ NOTREACHED();
+ return;
+ }
+
+ set_touch_extend(touch);
+}
+
+} // namespace ash
diff --git a/ash/wm/panels/attached_panel_window_targeter.h b/ash/wm/panels/attached_panel_window_targeter.h
new file mode 100644
index 0000000..d5e8196
--- /dev/null
+++ b/ash/wm/panels/attached_panel_window_targeter.h
@@ -0,0 +1,43 @@
+// Copyright 2014 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_WM_PANELS_ATTACHED_PANEL_WINDOW_TARGETER_H_
+#define ASH_WM_PANELS_ATTACHED_PANEL_WINDOW_TARGETER_H_
+
+#include "ash/shell_observer.h"
+#include "ui/wm/core/easy_resize_window_targeter.h"
+
+namespace ash {
+
+class PanelLayoutManager;
+
+// A window targeter installed on a panel container to disallow touch
+// hit-testing of attached panel edges that are adjacent to the shelf. This
+// makes it significantly easier to correctly target shelf buttons with touch.
+class AttachedPanelWindowTargeter : public ::wm::EasyResizeWindowTargeter,
+ public ShellObserver {
+ public:
+ AttachedPanelWindowTargeter(aura::Window* container,
+ const gfx::Insets& default_mouse_extend,
+ const gfx::Insets& default_touch_extend,
+ PanelLayoutManager* panel_layout_manager);
+ virtual ~AttachedPanelWindowTargeter();
+
+ // ShellObserver:
+ virtual void OnShelfCreatedForRootWindow(aura::Window* root_window) OVERRIDE;
+ virtual void OnShelfAlignmentChanged(aura::Window* root_window) OVERRIDE;
+
+ private:
+ void UpdateTouchExtend(aura::Window* root_window);
+
+ aura::Window* panel_container_;
+ PanelLayoutManager* panel_layout_manager_;
+ gfx::Insets default_touch_extend_;
+
+ DISALLOW_COPY_AND_ASSIGN(AttachedPanelWindowTargeter);
+};
+
+} // namespace ash
+
+#endif // ASH_WM_PANELS_ATTACHED_PANEL_WINDOW_TARGETER_H_
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc
index 853f648..d32eb82 100644
--- a/ash/wm/panels/panel_layout_manager_unittest.cc
+++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -35,6 +35,7 @@
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/events/event_utils.h"
#include "ui/views/widget/widget.h"
namespace ash {
@@ -59,9 +60,10 @@ class PanelLayoutManagerTest : public test::AshTestBase {
return CreateTestWindowInShellWithBounds(bounds);
}
- aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
+ aura::Window* CreatePanelWindowWithDelegate(aura::WindowDelegate* delegate,
+ const gfx::Rect& bounds) {
aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
- NULL, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
+ delegate, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
test::TestShelfDelegate* shelf_delegate =
test::TestShelfDelegate::instance();
shelf_delegate->AddShelfItem(window);
@@ -72,6 +74,10 @@ class PanelLayoutManagerTest : public test::AshTestBase {
return window;
}
+ aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
+ return CreatePanelWindowWithDelegate(NULL, bounds);
+ }
+
aura::Window* GetPanelContainer(aura::Window* panel) {
return Shell::GetContainer(panel->GetRootWindow(),
kShellWindowId_PanelContainer);
@@ -784,6 +790,73 @@ TEST_F(PanelLayoutManagerTest, PanelsHideAndRestoreWithShelf) {
EXPECT_TRUE(w3->IsVisible());
}
+// Verifies that touches along the attached edge of a panel do not
+// target the panel itself.
+TEST_F(PanelLayoutManagerTest, TouchHitTestPanel) {
+ aura::test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> w(
+ CreatePanelWindowWithDelegate(&delegate, gfx::Rect(0, 0, 200, 200)));
+ ui::EventTarget* root = w->GetRootWindow();
+ ui::EventTargeter* targeter = root->GetEventTargeter();
+
+ // Note that the constants used in the touch locations below are
+ // arbitrarily-selected small numbers which will ensure the point is
+ // within the default extended region surrounding the panel. This value
+ // is calculated as
+ // kResizeOutsideBoundsSize * kResizeOutsideBoundsScaleForTouch
+ // in src/ash/root_window_controller.cc.
+
+ // Hit test outside the right edge with a bottom-aligned shelf.
+ SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_BOTTOM);
+ gfx::Rect bounds(w->bounds());
+ ui::TouchEvent touch(ui::ET_TOUCH_PRESSED,
+ gfx::Point(bounds.right() + 3, bounds.y() + 2),
+ 0, ui::EventTimeForNow());
+ ui::EventTarget* target = targeter->FindTargetForEvent(root, &touch);
+ EXPECT_EQ(w.get(), target);
+
+ // Hit test outside the bottom edge with a bottom-aligned shelf.
+ touch.set_location(gfx::Point(bounds.x() + 6, bounds.bottom() + 5));
+ target = targeter->FindTargetForEvent(root, &touch);
+ EXPECT_NE(w.get(), target);
+
+ // Hit test outside the bottom edge with a right-aligned shelf.
+ SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT);
+ bounds = w->bounds();
+ touch.set_location(gfx::Point(bounds.x() + 6, bounds.bottom() + 5));
+ target = targeter->FindTargetForEvent(root, &touch);
+ EXPECT_EQ(w.get(), target);
+
+ // Hit test outside the right edge with a right-aligned shelf.
+ touch.set_location(gfx::Point(bounds.right() + 3, bounds.y() + 2));
+ target = targeter->FindTargetForEvent(root, &touch);
+ EXPECT_NE(w.get(), target);
+
+ // Hit test outside the top edge with a left-aligned shelf.
+ SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_LEFT);
+ bounds = w->bounds();
+ touch.set_location(gfx::Point(bounds.x() + 4, bounds.y() - 6));
+ target = targeter->FindTargetForEvent(root, &touch);
+ EXPECT_EQ(w.get(), target);
+
+ // Hit test outside the left edge with a left-aligned shelf.
+ touch.set_location(gfx::Point(bounds.x() - 1, bounds.y() + 5));
+ target = targeter->FindTargetForEvent(root, &touch);
+ EXPECT_NE(w.get(), target);
+
+ // Hit test outside the left edge with a top-aligned shelf.
+ SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_TOP);
+ bounds = w->bounds();
+ touch.set_location(gfx::Point(bounds.x() - 1, bounds.y() + 5));
+ target = targeter->FindTargetForEvent(root, &touch);
+ EXPECT_EQ(w.get(), target);
+
+ // Hit test outside the top edge with a top-aligned shelf.
+ touch.set_location(gfx::Point(bounds.x() + 4, bounds.y() - 6));
+ target = targeter->FindTargetForEvent(root, &touch);
+ EXPECT_NE(w.get(), target);
+}
+
INSTANTIATE_TEST_CASE_P(LtrRtl, PanelLayoutManagerTextDirectionTest,
testing::Bool());
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index 6056a2f..a2556cf 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -1461,8 +1461,8 @@ TEST_F(WorkspaceControllerTest, WindowEdgeHitTest) {
}
}
-// Verifies events targeting just outside the window edges for panels.
-TEST_F(WorkspaceControllerTest, WindowEdgeHitTestPanel) {
+// Verifies mouse event targeting just outside the window edges for panels.
+TEST_F(WorkspaceControllerTest, WindowEdgeMouseHitTestPanel) {
aura::test::TestWindowDelegate delegate;
scoped_ptr<Window> window(CreateTestPanel(&delegate,
gfx::Rect(20, 10, 100, 50)));
@@ -1491,10 +1491,38 @@ TEST_F(WorkspaceControllerTest, WindowEdgeHitTestPanel) {
EXPECT_EQ(window.get(), target);
else
EXPECT_NE(window.get(), target);
+ }
+}
+// Verifies touch event targeting just outside the window edges for panels.
+// The shelf is aligned to the bottom by default, and so touches just below
+// the bottom edge of the panel should not target the panel itself because
+// an AttachedPanelWindowTargeter is installed on the panel container.
+TEST_F(WorkspaceControllerTest, WindowEdgeTouchHitTestPanel) {
+ aura::test::TestWindowDelegate delegate;
+ scoped_ptr<Window> window(CreateTestPanel(&delegate,
+ gfx::Rect(20, 10, 100, 50)));
+ ui::EventTarget* root = window->GetRootWindow();
+ ui::EventTargeter* targeter = root->GetEventTargeter();
+ const gfx::Rect bounds = window->bounds();
+ const int kNumPoints = 5;
+ struct {
+ const char* direction;
+ gfx::Point location;
+ bool is_target_hit;
+ } points[kNumPoints] = {
+ { "left", gfx::Point(bounds.x() - 2, bounds.y() + 10), true },
+ { "top", gfx::Point(bounds.x() + 10, bounds.y() - 2), true },
+ { "right", gfx::Point(bounds.right() + 2, bounds.y() + 10), true },
+ { "bottom", gfx::Point(bounds.x() + 10, bounds.bottom() + 2), false },
+ { "outside", gfx::Point(bounds.x() + 10, bounds.y() - 31), false },
+ };
+ for (int i = 0; i < kNumPoints; ++i) {
+ SCOPED_TRACE(points[i].direction);
+ const gfx::Point& location = points[i].location;
ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, location, 0,
ui::EventTimeForNow());
- target = targeter->FindTargetForEvent(root, &touch);
+ ui::EventTarget* target = targeter->FindTargetForEvent(root, &touch);
if (points[i].is_target_hit)
EXPECT_EQ(window.get(), target);
else