summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorbruthig <bruthig@chromium.org>2015-02-13 07:13:52 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-13 15:14:41 +0000
commit7ec5114efa5eada853c2ece5d6edb0fa4ce5611a (patch)
treea2ac273507cfec0d24575e2e233d8fd5b01f107c /ash
parentda598af72344cb67f04108e80415372bed7cea66 (diff)
downloadchromium_src-7ec5114efa5eada853c2ece5d6edb0fa4ce5611a.zip
chromium_src-7ec5114efa5eada853c2ece5d6edb0fa4ce5611a.tar.gz
chromium_src-7ec5114efa5eada853c2ece5d6edb0fa4ce5611a.tar.bz2
Implemented swipe to close in overview mode.
BUG=393668 Review URL: https://codereview.chromium.org/690103008 Cr-Commit-Position: refs/heads/master@{#316217}
Diffstat (limited to 'ash')
-rw-r--r--ash/ash_switches.cc4
-rw-r--r--ash/ash_switches.h1
-rw-r--r--ash/wm/overview/overview_animation_type.h11
-rw-r--r--ash/wm/overview/scoped_overview_animation_settings.cc28
-rw-r--r--ash/wm/overview/scoped_overview_animation_settings.h5
-rw-r--r--ash/wm/overview/window_selector.cc1
-rw-r--r--ash/wm/overview/window_selector_controller.cc6
-rw-r--r--ash/wm/overview/window_selector_controller.h5
-rw-r--r--ash/wm/overview/window_selector_item.cc138
-rw-r--r--ash/wm/overview/window_selector_item.h24
-rw-r--r--ash/wm/overview/window_selector_unittest.cc300
11 files changed, 463 insertions, 60 deletions
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc
index f11743dd..05fabb2 100644
--- a/ash/ash_switches.cc
+++ b/ash/ash_switches.cc
@@ -39,6 +39,10 @@ const char kAshDisableScreenOrientationLock[] =
"ash-disable-screen-orientation-lock";
#endif
+// Disables gesture swipe to close windows while in Overview mode.
+const char kAshDisableSwipeToCloseInOverviewMode[] =
+ "ash-disable-swipe-to-close-in-overview-mode";
+
// Disable the Touch Exploration Mode. Touch Exploration Mode will no longer be
// turned on automatically when spoken feedback is enabled when this flag is
// set.
diff --git a/ash/ash_switches.h b/ash/ash_switches.h
index 4edb61e..50c8aca 100644
--- a/ash/ash_switches.h
+++ b/ash/ash_switches.h
@@ -22,6 +22,7 @@ ASH_EXPORT extern const char kAshConstrainPointerToRoot[];
ASH_EXPORT extern const char kAshCopyHostBackgroundAtBoot[];
ASH_EXPORT extern const char kAshDebugShortcuts[];
ASH_EXPORT extern const char kAshDisableLockLayoutManager[];
+ASH_EXPORT extern const char kAshDisableSwipeToCloseInOverviewMode[];
#if defined(OS_CHROMEOS)
ASH_EXPORT extern const char kAshDisableScreenOrientationLock[];
#endif
diff --git a/ash/wm/overview/overview_animation_type.h b/ash/wm/overview/overview_animation_type.h
index 391ce8e..5df51cb 100644
--- a/ash/wm/overview/overview_animation_type.h
+++ b/ash/wm/overview/overview_animation_type.h
@@ -12,8 +12,10 @@ enum OverviewAnimationType {
// TODO(bruthig): Remove OVERVIEW_ANIMATION_NONE value and replace it with
// correct animation type actions.
OVERVIEW_ANIMATION_NONE,
- // Used to fade in the close button and label when entering overview mode.
+ // Used to fade in the close button and label.
OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN,
+ // Used to fade out the close button.
+ OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT,
// Used to position windows when entering/exiting overview mode and when a
// window is closed while overview mode is active.
OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS,
@@ -21,7 +23,12 @@ enum OverviewAnimationType {
OVERVIEW_ANIMATION_HIDE_WINDOW,
// Used to restore windows to their original position when exiting overview
// mode.
- OVERVIEW_ANIMATION_RESTORE_WINDOW
+ OVERVIEW_ANIMATION_RESTORE_WINDOW,
+ // Used to animate windows when a user performs a touch drag gesture.
+ OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM,
+ // Used to animate windows back in to position when a touch drag gesture is
+ // cancelled.
+ OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL
};
} // namespace ash
diff --git a/ash/wm/overview/scoped_overview_animation_settings.cc b/ash/wm/overview/scoped_overview_animation_settings.cc
index 9dc172d..3cb6bcb 100644
--- a/ash/wm/overview/scoped_overview_animation_settings.cc
+++ b/ash/wm/overview/scoped_overview_animation_settings.cc
@@ -20,15 +20,22 @@ const int kTransitionMilliseconds = 200;
// The time duration for widgets to fade in.
const int kFadeInMilliseconds = 80;
+// The time duration for widgets to fade out.
+const int kFadeOutMilliseconds = 100;
+
base::TimeDelta GetAnimationDuration(OverviewAnimationType animation_type) {
switch (animation_type) {
case OVERVIEW_ANIMATION_NONE:
+ case OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM:
return base::TimeDelta();
case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN:
return base::TimeDelta::FromMilliseconds(kFadeInMilliseconds);
+ case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT:
+ return base::TimeDelta::FromMilliseconds(kFadeOutMilliseconds);
case OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS:
case OVERVIEW_ANIMATION_RESTORE_WINDOW:
case OVERVIEW_ANIMATION_HIDE_WINDOW:
+ case OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL:
return base::TimeDelta::FromMilliseconds(kTransitionMilliseconds);
}
NOTREACHED();
@@ -44,6 +51,7 @@ ScopedOverviewAnimationSettings::ScopedOverviewAnimationSettings(
switch (animation_type) {
case OVERVIEW_ANIMATION_NONE:
+ case OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM:
animation_settings_.SetPreemptionStrategy(
ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
break;
@@ -55,6 +63,10 @@ ScopedOverviewAnimationSettings::ScopedOverviewAnimationSettings(
animation_settings_.SetPreemptionStrategy(
ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
break;
+ case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT:
+ animation_settings_.SetPreemptionStrategy(
+ ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
+ break;
case OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS:
case OVERVIEW_ANIMATION_RESTORE_WINDOW:
animation_settings_.SetPreemptionStrategy(
@@ -65,6 +77,11 @@ ScopedOverviewAnimationSettings::ScopedOverviewAnimationSettings(
animation_settings_.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
break;
+ case OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL:
+ animation_settings_.SetPreemptionStrategy(
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+ animation_settings_.SetTweenType(gfx::Tween::EASE_IN_OUT);
+ break;
}
animation_settings_.SetTransitionDuration(
GetAnimationDuration(animation_type));
@@ -73,15 +90,4 @@ ScopedOverviewAnimationSettings::ScopedOverviewAnimationSettings(
ScopedOverviewAnimationSettings::~ScopedOverviewAnimationSettings() {
}
-// static:
-void ScopedOverviewAnimationSettings::SetupFadeInAfterLayout(
- aura::Window* window) {
- ui::Layer* layer = window->layer();
- layer->SetOpacity(0.0f);
- ScopedOverviewAnimationSettings animation_settings(
- OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN,
- window);
- layer->SetOpacity(1.0f);
-}
-
} // namespace ash
diff --git a/ash/wm/overview/scoped_overview_animation_settings.h b/ash/wm/overview/scoped_overview_animation_settings.h
index 4ea09e5..a558c7e 100644
--- a/ash/wm/overview/scoped_overview_animation_settings.h
+++ b/ash/wm/overview/scoped_overview_animation_settings.h
@@ -24,11 +24,6 @@ class ScopedOverviewAnimationSettings {
aura::Window* window);
virtual ~ScopedOverviewAnimationSettings();
- // Convenvience method to fade in a Window with predefined animation settings.
- // Note: The fade in animation will occur after a delay where the delay is how
- // long the lay out animations take.
- static void SetupFadeInAfterLayout(aura::Window* window);
-
private:
// The managed animation settings.
ui::ScopedLayerAnimationSettings animation_settings_;
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index de86abe..6230b9b 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -5,6 +5,7 @@
#include "ash/wm/overview/window_selector.h"
#include <algorithm>
+#include <functional>
#include <set>
#include <vector>
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index df14d27..69ad590 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -6,6 +6,7 @@
#include <vector>
+#include "ash/ash_switches.h"
#include "ash/metrics/user_metrics_recorder.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_state_delegate.h"
@@ -15,12 +16,15 @@
#include "ash/wm/overview/window_selector.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
+#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "ui/aura/window.h"
namespace ash {
-WindowSelectorController::WindowSelectorController() {
+WindowSelectorController::WindowSelectorController()
+ : swipe_to_close_disabled_(base::CommandLine::ForCurrentProcess()->
+ HasSwitch(switches::kAshDisableSwipeToCloseInOverviewMode)) {
}
WindowSelectorController::~WindowSelectorController() {
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h
index 8d4a625..3a87904 100644
--- a/ash/wm/overview/window_selector_controller.h
+++ b/ash/wm/overview/window_selector_controller.h
@@ -48,6 +48,8 @@ class ASH_EXPORT WindowSelectorController
// are visible during overview mode.
bool IsRestoringMinimizedWindows() const;
+ bool swipe_to_close_disabled() const { return swipe_to_close_disabled_; }
+
// WindowSelectorDelegate:
void OnSelectionEnded() override;
@@ -60,6 +62,9 @@ class ASH_EXPORT WindowSelectorController
scoped_ptr<WindowSelector> window_selector_;
base::Time last_selection_time_;
+ // Tracks whether the "Swipe-to-close" feature is disabled.
+ bool swipe_to_close_disabled_;
+
DISALLOW_COPY_AND_ASSIGN(WindowSelectorController);
};
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 13b52b7..2559362 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -37,6 +37,13 @@ namespace ash {
namespace {
+// The minimum fling velocity which will cause a window to be closed. Unit is
+// pixels per second.
+const float kMinimumFlingVelocity = 4000.0f;
+
+// The minimum opacity used during touch scroll gestures.
+const float kMinimumOpacity = 0.2f;
+
// In the conceptual overview table, the window margin is the space reserved
// around the window within the cell. This margin does not overlap so the
// closest distance between adjacent windows will be twice this amount.
@@ -72,6 +79,36 @@ gfx::Rect GetTransformedBounds(aura::Window* window) {
return ToEnclosingRect(bounds);
}
+// Convenvience method to fade in a Window with predefined animation settings.
+// Note: The fade in animation will occur after a delay where the delay is how
+// long the lay out animations take.
+void SetupFadeInAfterLayout(aura::Window* window) {
+ ui::Layer* layer = window->layer();
+ layer->SetOpacity(0.0f);
+ ScopedOverviewAnimationSettings animation_settings(
+ OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN,
+ window);
+ layer->SetOpacity(1.0f);
+}
+
+// Convenience method to fade out a window using the animation settings defined
+// by OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT.
+void SetupFadeOut(aura::Window* window) {
+ ScopedOverviewAnimationSettings animation_settings(
+ OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT,
+ window);
+ window->layer()->SetOpacity(0.0f);
+}
+
+// Calculates the window opacity from the given scroll |distance| and the
+// |min opacity_distance|.
+float CalculateOpacityFromScrollDistance(int distance,
+ int min_opacity_distance) {
+ float opacity =
+ 1.0f - static_cast<float>(abs(distance)) / min_opacity_distance;
+ return std::min(1.0f, std::max(kMinimumOpacity, opacity));
+}
+
// An image button with a close window icon.
class OverviewCloseButton : public views::ImageButton {
public:
@@ -99,9 +136,10 @@ OverviewCloseButton::~OverviewCloseButton() {
} // namespace
WindowSelectorItem::OverviewLabelButton::OverviewLabelButton(
- views::ButtonListener* listener,
+ WindowSelectorItem* selector_item,
const base::string16& text)
- : LabelButton(listener, text),
+ : LabelButton(selector_item, text),
+ selector_item_(selector_item),
top_padding_(0) {
}
@@ -114,6 +152,12 @@ gfx::Rect WindowSelectorItem::OverviewLabelButton::GetChildAreaBounds() {
return bounds;
}
+void WindowSelectorItem::OverviewLabelButton::OnGestureEvent(
+ ui::GestureEvent* event) {
+ selector_item_->OnGestureEvent(event);
+ views::LabelButton::OnGestureEvent(event);
+}
+
WindowSelectorItem::WindowSelectorItem(aura::Window* window)
: dimmed_(false),
root_window_(window->GetRootWindow()),
@@ -216,6 +260,72 @@ void WindowSelectorItem::ButtonPressed(views::Button* sender,
wm::GetWindowState(transform_window_.window())->Activate();
}
+void WindowSelectorItem::OnGestureEvent(ui::GestureEvent* event) {
+ if (Shell::GetInstance()->window_selector_controller()->
+ swipe_to_close_disabled())
+ return;
+
+ int delta_x = 0;
+ if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN)
+ scroll_x_origin_ = event->x();
+ else
+ delta_x = event->x() - scroll_x_origin_;
+
+ switch (event->type()) {
+ case ui::ET_GESTURE_SCROLL_BEGIN: {
+ // We need to call SetHandled() for the ET_GESTURE_SCROLL_BEGIN event so
+ // that future ET_GESTURE_SCROLL_* events are sent here.
+ event->SetHandled();
+ close_button_->SetEnabled(false);
+ SetupFadeOut(close_button_widget_.GetNativeWindow());
+ break;
+ }
+ case ui::ET_GESTURE_SCROLL_UPDATE: {
+ event->SetHandled();
+ ScopedTransformOverviewWindow::ScopedAnimationSettings
+ animation_settings;
+ transform_window_.BeginScopedAnimation(
+ OverviewAnimationType::OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM,
+ &animation_settings);
+
+ gfx::Transform new_transform;
+ new_transform.Translate(delta_x, 0);
+ new_transform.PreconcatTransform(
+ transform_window_.get_overview_transform());
+ transform_window_.SetTransform(root_window(), new_transform);
+
+ const float opacity = CalculateOpacityFromScrollDistance(delta_x,
+ GetMinimumCloseDistance());
+ transform_window_.SetOpacity(opacity);
+ break;
+ }
+ case ui::ET_GESTURE_SCROLL_END: {
+ event->SetHandled();
+ if (abs(delta_x) > GetMinimumCloseDistance()) {
+ transform_window_.Close();
+ break;
+ }
+ ResetScrolledWindow();
+ break;
+ }
+ case ui::ET_SCROLL_FLING_START: {
+ event->SetHandled();
+ if (abs(delta_x) > GetMinimumCloseDistance() ||
+ fabs(event->details().velocity_x()) > kMinimumFlingVelocity) {
+ transform_window_.Close();
+ break;
+ }
+ ResetScrolledWindow();
+ break;
+ }
+ case ui::ET_GESTURE_END:
+ scroll_x_origin_ = 0;
+ break;
+ default:
+ break;
+ }
+}
+
void WindowSelectorItem::OnWindowDestroying(aura::Window* window) {
window->RemoveObserver(this);
transform_window_.OnWindowDestroyed();
@@ -228,6 +338,20 @@ void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) {
UpdateCloseButtonAccessibilityName();
}
+void WindowSelectorItem::ResetScrolledWindow() {
+ ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings;
+ transform_window_.BeginScopedAnimation(
+ OverviewAnimationType::OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL,
+ &animation_settings);
+
+ transform_window_.SetTransform(root_window(),
+ transform_window_.get_overview_transform());
+ transform_window_.SetOpacity(1.0);
+
+ SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow());
+ close_button_->SetEnabled(true);
+}
+
void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds,
OverviewAnimationType animation_type) {
DCHECK(root_window_ == GetWindow()->GetRootWindow());
@@ -261,8 +385,7 @@ void WindowSelectorItem::UpdateWindowLabel(
if (!window_label_->IsVisible()) {
window_label_->Show();
- ScopedOverviewAnimationSettings::SetupFadeInAfterLayout(
- window_label_->GetNativeWindow());
+ SetupFadeInAfterLayout(window_label_->GetNativeWindow());
}
gfx::Rect converted_bounds =
@@ -311,8 +434,7 @@ void WindowSelectorItem::UpdateCloseButtonLayout(
OverviewAnimationType animation_type) {
if (!close_button_->visible()) {
close_button_->SetVisible(true);
- ScopedOverviewAnimationSettings::SetupFadeInAfterLayout(
- close_button_widget_.GetNativeWindow());
+ SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow());
}
ScopedOverviewAnimationSettings animation_settings(animation_type,
close_button_widget_.GetNativeWindow());
@@ -334,4 +456,8 @@ void WindowSelectorItem::UpdateCloseButtonAccessibilityName() {
GetWindow()->title()));
}
+int WindowSelectorItem::GetMinimumCloseDistance() const {
+ return target_bounds_.size().width() / 2;
+}
+
} // namespace ash
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 063b141..0e4aa8f 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -33,18 +33,25 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
public:
class OverviewLabelButton : public views::LabelButton {
public:
- OverviewLabelButton(views::ButtonListener* listener,
+ OverviewLabelButton(WindowSelectorItem* selector_item,
const base::string16& text);
~OverviewLabelButton() override;
void set_top_padding(int top_padding) { top_padding_ = top_padding; }
+ // views::LabelButton:
+ void OnGestureEvent(ui::GestureEvent* event) override;
+
protected:
// views::LabelButton:
gfx::Rect GetChildAreaBounds() override;
private:
+ // The WindowSelectorItem that the touch gestures are delegated to.
+ // Not owned.
+ WindowSelectorItem* selector_item_;
+
// Padding on top of the button.
int top_padding_;
@@ -94,6 +101,9 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
const gfx::Rect& target_bounds() const { return target_bounds_; }
+ // Handles the gestures on the Window
+ void OnGestureEvent(ui::GestureEvent* event);
+
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
@@ -127,6 +137,14 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
// Updates the close buttons accessibility name.
void UpdateCloseButtonAccessibilityName();
+ // Animates the |transform_window_| back to it's original overview mode
+ // position.
+ void ResetScrolledWindow();
+
+ // Returns the minimum distance at which a scroll gesture will cause this
+ // selector item to be closed.
+ int GetMinimumCloseDistance() const;
+
// True if the item is being shown in the overview, false if it's being
// filtered.
bool dimmed_;
@@ -158,6 +176,10 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
// close_button_widget_.
views::ImageButton* close_button_;
+ // The original X location for a scroll begin event. |original_x_| is in the
+ // local coordinate space of |window_label_button_view_|.
+ float scroll_x_origin_;
+
DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem);
};
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index fef9b75..a663b5c 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -3,8 +3,11 @@
// found in the LICENSE file.
#include <algorithm>
+#include <map>
+#include <vector>
#include "ash/accessibility_delegate.h"
+#include "ash/ash_switches.h"
#include "ash/drag_drop/drag_drop_controller.h"
#include "ash/root_window_controller.h"
#include "ash/screen_util.h"
@@ -28,6 +31,7 @@
#include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h"
#include "base/basictypes.h"
+#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_vector.h"
#include "base/run_loop.h"
@@ -68,8 +72,22 @@ void CancelDrag(DragDropController* controller, bool* canceled) {
}
}
+// A short drag distance that will not cause an overview item to close.
+const int kShortDragDistance = 10;
+
+// A far drag distance that will cause an overview item to close.
+const int kFarDragDistance = 200;
+
+// A slow fling velocity that should not cause selctor items to close.
+const int kSlowFlingVelocity = 2000;
+
+// A fast fling velocity that should cause selector items to close.
+const int kFastFlingVelocity = 5000;
+
} // namespace
+// TODO(bruthig): Move all non-simple method definitions out of class
+// declaration.
class WindowSelectorTest : public test::AshTestBase {
public:
WindowSelectorTest() {}
@@ -99,24 +117,28 @@ class WindowSelectorTest : public test::AshTestBase {
return window;
}
- aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
- aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
- nullptr, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
- test::TestShelfDelegate::instance()->AddShelfItem(window);
- shelf_view_test()->RunMessageLoopUntilAnimationsDone();
- return window;
- }
-
- views::Widget* CreatePanelWindowWidget(const gfx::Rect& bounds) {
- views::Widget* widget = new views::Widget;
+ // Creates a Widget containing a Window with the given |bounds|. This should
+ // be used when the test requires a Widget. For example any test that will
+ // cause a window to be closed via
+ // views::Widget::GetWidgetForNativeView(window)->Close().
+ scoped_ptr<views::Widget> CreateWindowWidget(const gfx::Rect& bounds) {
+ scoped_ptr<views::Widget> widget(new views::Widget);
views::Widget::InitParams params;
params.bounds = bounds;
- params.type = views::Widget::InitParams::TYPE_PANEL;
+ params.type = views::Widget::InitParams::TYPE_WINDOW;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget->Init(params);
widget->Show();
ParentWindowInPrimaryRootWindow(widget->GetNativeWindow());
- return widget;
+ return widget.Pass();
+ }
+
+ aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
+ aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
+ nullptr, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
+ test::TestShelfDelegate::instance()->AddShelfItem(window);
+ shelf_view_test()->RunMessageLoopUntilAnimationsDone();
+ return window;
}
bool WindowsOverlapping(aura::Window* window1, aura::Window* window2) {
@@ -256,6 +278,24 @@ class WindowSelectorTest : public test::AshTestBase {
DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest);
};
+class WindowSelectorSwipeToCloseDisabledTest : public WindowSelectorTest {
+ public:
+ WindowSelectorSwipeToCloseDisabledTest() {}
+ ~WindowSelectorSwipeToCloseDisabledTest() override {}
+
+ // WindowSelectorTest:
+ void SetUp() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WindowSelectorSwipeToCloseDisabledTest);
+};
+
+void WindowSelectorSwipeToCloseDisabledTest::SetUp() {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kAshDisableSwipeToCloseInOverviewMode);
+ WindowSelectorTest::SetUp();
+}
+
// Tests that an a11y alert is sent on entering overview mode.
TEST_F(WindowSelectorTest, A11yAlertOnOverviewMode) {
gfx::Rect bounds(0, 0, 400, 400);
@@ -325,15 +365,6 @@ TEST_F(WindowSelectorTest, BasicGesture) {
TEST_F(WindowSelectorTest, NoCrashWithDesktopTap) {
scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(200, 300, 250, 450)));
- // We need a widget for the close button to work, a bare window will crash.
- scoped_ptr<views::Widget> widget(new views::Widget);
- views::Widget::InitParams params;
- params.bounds = gfx::Rect(0, 0, 400, 400);
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.parent = window->parent();
- widget->Init(params);
- widget->Show();
-
ToggleOverview();
gfx::Rect bounds =
@@ -428,22 +459,15 @@ TEST_F(WindowSelectorTest, WindowDoesNotReceiveEvents) {
// Tests that clicking on the close button effectively closes the window.
TEST_F(WindowSelectorTest, CloseButton) {
- scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(200, 300, 250, 450)));
+ scoped_ptr<views::Widget> widget =
+ CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
- // We need a widget for the close button to work, a bare window will crash.
- scoped_ptr<views::Widget> widget(new views::Widget);
- views::Widget::InitParams params;
- params.bounds = gfx::Rect(0, 0, 400, 400);
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.parent = window1->parent();
- widget->Init(params);
- widget->Show();
ToggleOverview();
- aura::Window* window2 = widget->GetNativeWindow();
- gfx::RectF bounds = GetTransformedBoundsInRootWindow(window2);
+ aura::Window* window = widget->GetNativeWindow();
+ gfx::RectF bounds = GetTransformedBoundsInRootWindow(window);
gfx::Point point(bounds.top_right().x() - 1, bounds.top_right().y() - 1);
- ui::test::EventGenerator event_generator(window2->GetRootWindow(), point);
+ ui::test::EventGenerator event_generator(window->GetRootWindow(), point);
EXPECT_FALSE(widget->IsClosed());
event_generator.ClickLeftButton();
@@ -461,7 +485,10 @@ TEST_F(WindowSelectorTest, CloseButtonOnMultipleDisplay) {
scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(650, 300, 250, 450)));
- // We need a widget for the close button to work, a bare window will crash.
+ // We need a widget for the close button to work because windows are closed
+ // via the widget. We also use the widget to determine if the window has been
+ // closed or not. We explicity create the widget so that the window can be
+ // parented to a non-primary root window.
scoped_ptr<views::Widget> widget(new views::Widget);
views::Widget::InitParams params;
params.bounds = gfx::Rect(650, 0, 400, 400);
@@ -1246,4 +1273,209 @@ TEST_F(WindowSelectorTest, CancelOverviewOnTap) {
EXPECT_FALSE(IsSelecting());
}
+// Verify swipe to close doesn't work when swipe to close is disabled.
+TEST_F(WindowSelectorSwipeToCloseDisabledTest, WindowTapDragFarDistance) {
+ scoped_ptr<views::Widget> widget =
+ CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
+
+ ToggleOverview();
+ ASSERT_TRUE(IsSelecting());
+
+ aura::Window* window = widget->GetNativeWindow();
+ gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window));
+ ui::test::EventGenerator event_generator(window->GetRootWindow());
+
+ ASSERT_FALSE(widget->IsClosed());
+
+ gfx::Point start(bounds.CenterPoint());
+ gfx::Point end(start.x() - kFarDragDistance, start.y());
+ event_generator.GestureScrollSequence(
+ start, end, base::TimeDelta::FromMilliseconds(10), 5);
+
+ EXPECT_FALSE(widget->IsClosed());
+
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(IsSelecting());
+}
+
+// Verify the window moves and fades as it is dragged.
+TEST_F(WindowSelectorTest, VerifyWindowBehaviourDuringTapDrag) {
+ scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
+
+ ToggleOverview();
+
+ gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(
+ window.get()));
+ ui::test::EventGenerator event_generator(window->GetRootWindow());
+
+ const gfx::Point drag_start_point(bounds.CenterPoint());
+ const gfx::Point drag_left_point(drag_start_point.x() - kFarDragDistance,
+ drag_start_point.y());
+ const gfx::Point drag_right_point(drag_start_point.x() + kFarDragDistance,
+ drag_start_point.y());
+
+ const int drag_left_delta_x = drag_start_point.x() - drag_left_point.x();
+ const int drag_right_delta_x = drag_start_point.x() - drag_right_point.x();
+
+ const gfx::Rect original_bounds = window->GetBoundsInScreen();
+
+ ASSERT_EQ(1.0f, window->layer()->opacity());
+
+ event_generator.set_current_location(drag_start_point);
+ event_generator.PressTouch();
+
+ EXPECT_EQ(1.0f, window->layer()->opacity());
+
+ event_generator.MoveTouch(drag_left_point);
+
+ EXPECT_EQ(original_bounds.x() - drag_left_delta_x,
+ window->GetBoundsInScreen().x());
+ EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y());
+
+ EXPECT_LT(window->layer()->opacity(), 0.5f);
+
+ event_generator.MoveTouch(drag_start_point);
+
+ EXPECT_EQ(original_bounds.x(), window->GetBoundsInScreen().x());
+ EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y());
+ EXPECT_EQ(1.0f, window->layer()->opacity());
+
+ event_generator.MoveTouch(drag_right_point);
+
+ EXPECT_EQ(original_bounds.x() - drag_right_delta_x,
+ window->GetBoundsInScreen().x());
+ EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y());
+
+ EXPECT_LT(window->layer()->opacity(), 0.5f);
+}
+
+// Test dragging a window a short distance.
+TEST_F(WindowSelectorTest, WindowTapDragShortDistance) {
+ scoped_ptr<views::Widget> widget =
+ CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
+
+ ToggleOverview();
+
+ aura::Window* window = widget->GetNativeWindow();
+ gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window));
+ ui::test::EventGenerator event_generator(window->GetRootWindow());
+
+ ASSERT_FALSE(widget->IsClosed());
+
+ gfx::Point start(bounds.CenterPoint());
+ gfx::Point end(start.x() - kShortDragDistance, start.y());
+ event_generator.GestureScrollSequence(
+ start, end, base::TimeDelta::FromMilliseconds(10), 5);
+
+ EXPECT_FALSE(widget->IsClosed());
+
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(IsSelecting());
+}
+
+// Test dragging a window a far distance.
+TEST_F(WindowSelectorTest, WindowTapDragFarDistance) {
+ scoped_ptr<views::Widget> widget =
+ CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
+
+ ToggleOverview();
+ ASSERT_TRUE(IsSelecting());
+
+ aura::Window* window = widget->GetNativeWindow();
+ gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window));
+ ui::test::EventGenerator event_generator(window->GetRootWindow());
+
+ ASSERT_FALSE(widget->IsClosed());
+
+ gfx::Point start(bounds.CenterPoint());
+ gfx::Point end(start.x() - kFarDragDistance, start.y());
+ event_generator.GestureScrollSequence(
+ start, end, base::TimeDelta::FromMilliseconds(10), 5);
+
+ EXPECT_TRUE(widget->IsClosed());
+
+ RunAllPendingInMessageLoop();
+ EXPECT_FALSE(IsSelecting());
+}
+
+// Test a slow velocity fling.
+TEST_F(WindowSelectorTest, SlowVelocityFling) {
+ scoped_ptr<views::Widget> widget =
+ CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
+
+ ToggleOverview();
+
+ aura::Window* window = widget->GetNativeWindow();
+ gfx::RectF bounds = GetTransformedBoundsInRootWindow(window);
+ ui::test::EventGenerator event_generator(window->GetRootWindow());
+
+ ASSERT_FALSE(widget->IsClosed());
+
+ gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y());
+ gfx::Point end(start.x() - kShortDragDistance, start.y());
+ const base::TimeDelta kScrollDuration =
+ event_generator.CalculateScrollDurationForFlingVelocity(
+ start, end, kSlowFlingVelocity, 10);
+ event_generator.GestureScrollSequence(start, end, kScrollDuration, 10);
+
+ EXPECT_FALSE(widget->IsClosed());
+
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(IsSelecting());
+}
+
+// Test a fast velocity fling.
+TEST_F(WindowSelectorTest, FastVelocityFling) {
+ scoped_ptr<views::Widget> widget =
+ CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
+
+ ToggleOverview();
+ ASSERT_TRUE(IsSelecting());
+
+ aura::Window* window = widget->GetNativeWindow();
+ gfx::RectF bounds = GetTransformedBoundsInRootWindow(window);
+ ui::test::EventGenerator event_generator(window->GetRootWindow());
+
+ ASSERT_FALSE(widget->IsClosed());
+
+ gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y());
+ gfx::Point end(start.x() - kShortDragDistance, start.y());
+ const base::TimeDelta kScrollDuration =
+ event_generator.CalculateScrollDurationForFlingVelocity(
+ start, end, kFastFlingVelocity, 10);
+ event_generator.GestureScrollSequence(start, end, kScrollDuration, 10);
+
+ EXPECT_TRUE(widget->IsClosed());
+
+ RunAllPendingInMessageLoop();
+ EXPECT_FALSE(IsSelecting());
+}
+
+// Test a fast velocity fling.
+TEST_F(WindowSelectorTest, SlowVelocityFlingAtAFarDistance) {
+ scoped_ptr<views::Widget> widget =
+ CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
+
+ ToggleOverview();
+ ASSERT_TRUE(IsSelecting());
+
+ aura::Window* window = widget->GetNativeWindow();
+ gfx::RectF bounds = GetTransformedBoundsInRootWindow(window);
+ ui::test::EventGenerator event_generator(window->GetRootWindow());
+
+ ASSERT_FALSE(widget->IsClosed());
+
+ gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y());
+ gfx::Point end(start.x() - kFarDragDistance, start.y());
+ const base::TimeDelta kScrollDuration =
+ event_generator.CalculateScrollDurationForFlingVelocity(
+ start, end, kSlowFlingVelocity, 10);
+ event_generator.GestureScrollSequence(start, end, kScrollDuration, 10);
+
+ EXPECT_TRUE(widget->IsClosed());
+
+ RunAllPendingInMessageLoop();
+ EXPECT_FALSE(IsSelecting());
+}
+
} // namespace ash