summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorvarunjain@chromium.org <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-26 22:14:37 +0000
committervarunjain@chromium.org <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-26 22:14:37 +0000
commit62531e1316efc119fd1342b367b8f6e7b6007c7a (patch)
tree0ff5d2ffcd7800172e241cfce7067716552dedfb /ash
parenta1ea5a9a54154af76ff112ccc363018aa8d985f7 (diff)
downloadchromium_src-62531e1316efc119fd1342b367b8f6e7b6007c7a.zip
chromium_src-62531e1316efc119fd1342b367b8f6e7b6007c7a.tar.gz
chromium_src-62531e1316efc119fd1342b367b8f6e7b6007c7a.tar.bz2
GestureRecognizer: Long press should be cancelled on prevented-defaulted moves.
BUG=133375 TEST=added new test Review URL: https://chromiumcodereview.appspot.com/10626009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144295 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/wm/system_gesture_event_filter.cc166
-rw-r--r--ash/wm/system_gesture_event_filter.h50
-rw-r--r--ash/wm/system_gesture_event_filter_unittest.cc81
3 files changed, 209 insertions, 88 deletions
diff --git a/ash/wm/system_gesture_event_filter.cc b/ash/wm/system_gesture_event_filter.cc
index 4af722d..2be1782 100644
--- a/ash/wm/system_gesture_event_filter.cc
+++ b/ash/wm/system_gesture_event_filter.cc
@@ -18,17 +18,14 @@
#include "ash/wm/window_util.h"
#include "ash/wm/workspace/phantom_window_controller.h"
#include "ash/wm/workspace/snap_sizer.h"
-#include "base/timer.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/aura/event.h"
#include "ui/aura/root_window.h"
-#include "ui/base/animation/animation.h"
-#include "ui/base/animation/animation_delegate.h"
-#include "ui/base/animation/linear_animation.h"
#include "ui/base/gestures/gesture_configuration.h"
+#include "ui/base/gestures/gesture_util.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/point.h"
@@ -87,13 +84,19 @@ Widget* CreateAffordanceWidget() {
return widget;
}
+} // namespace
+
+namespace ash {
+namespace internal {
+
// View of the LongPressAffordanceAnimation. Draws the actual contents and
// updates as the animation proceeds. It also maintains the views::Widget that
// the animation is shown in.
// Currently the affordance is to simply show an empty circle and fill it up as
// the animation proceeds.
// TODO(varunjain): Change the look of this affordance when we get official UX.
-class LongPressAffordanceView : public views::View {
+class LongPressAffordanceAnimation::LongPressAffordanceView
+ : public views::View {
public:
explicit LongPressAffordanceView(const gfx::Point& event_location)
: views::View(),
@@ -112,7 +115,6 @@ class LongPressAffordanceView : public views::View {
}
virtual ~LongPressAffordanceView() {
- widget_->Hide();
}
void UpdateWithAnimation(ui::Animation* animation) {
@@ -148,100 +150,94 @@ class LongPressAffordanceView : public views::View {
canvas->DrawPath(path, paint);
}
- scoped_ptr<Widget> widget_;
+ scoped_ptr<views::Widget> widget_;
int current_angle_;
DISALLOW_COPY_AND_ASSIGN(LongPressAffordanceView);
};
-} // namespace
-
-namespace ash {
-namespace internal {
+LongPressAffordanceAnimation::LongPressAffordanceAnimation()
+ : ui::LinearAnimation(kAffordanceFrameRateHz, this),
+ view_(NULL),
+ tap_down_target_(NULL) {
+ int duration =
+ ui::GestureConfiguration::long_press_time_in_seconds() * 1000 -
+ ui::GestureConfiguration::semi_long_press_time_in_seconds() * 1000;
+ SetDuration(duration);
+}
-// LongPressAffordanceAnimation displays an animated affordance that is shown
-// on a TAP_DOWN gesture. The animation completes on a LONG_PRESS gesture, or is
-// canceled and hidden if any other event is received before that.
-class SystemGestureEventFilter::LongPressAffordanceAnimation
- : public ui::AnimationDelegate,
- public ui::LinearAnimation {
- public:
- LongPressAffordanceAnimation()
- : ui::LinearAnimation(kAffordanceFrameRateHz, this),
- view_(NULL) {
- int duration =
- ui::GestureConfiguration::long_press_time_in_seconds() * 1000 -
- ui::GestureConfiguration::semi_long_press_time_in_seconds() * 1000;
- SetDuration(duration);
- }
+LongPressAffordanceAnimation::~LongPressAffordanceAnimation() {}
- void ProcessEvent(aura::Window* target, aura::LocatedEvent* event) {
- gfx::Point event_location;
- int64 timer_start_time_ms =
- ui::GestureConfiguration::semi_long_press_time_in_seconds() * 1000;
- switch (event->type()) {
- case ui::ET_GESTURE_TAP_DOWN:
- // Start animation.
- tap_down_location_ = event->root_location();
- timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(timer_start_time_ms),
- this,
- &LongPressAffordanceAnimation::StartAnimation);
- break;
- case ui::ET_TOUCH_MOVED:
- // We do not want to stop the animation on every TOUCH_MOVED. Instead,
- // we will rely on SCROLL_BEGIN to break the animation when the user
- // moves their finger.
- break;
- case ui::ET_GESTURE_LONG_PRESS:
- if (is_animating())
- End();
- // fall through to default to reset the view.
- default:
- // On all other touch and gesture events, we hide the animation.
+void LongPressAffordanceAnimation::ProcessEvent(aura::Window* target,
+ aura::LocatedEvent* event) {
+ // Once we have a target, we are only interested in events on that target.
+ if (tap_down_target_ && tap_down_target_ != target)
+ return;
+ int64 timer_start_time_ms =
+ ui::GestureConfiguration::semi_long_press_time_in_seconds() * 1000;
+ switch (event->type()) {
+ case ui::ET_GESTURE_TAP_DOWN:
+ // Start animation.
+ tap_down_location_ = event->root_location();
+ tap_down_target_ = target;
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(timer_start_time_ms),
+ this,
+ &LongPressAffordanceAnimation::StartAnimation);
+ break;
+ case ui::ET_TOUCH_MOVED:
+ // If animation is running, We want it to be robust to small finger
+ // movements. So we stop the animation only when the finger moves a
+ // certain distance.
+ if (is_animating() && !ui::gestures::IsInsideManhattanSquare(
+ event->root_location(), tap_down_location_))
StopAnimation();
- break;
- }
- }
-
- private:
- void StartAnimation() {
- view_.reset(new LongPressAffordanceView(tap_down_location_));
- Start();
- }
-
- void StopAnimation() {
- if (timer_.IsRunning())
- timer_.Stop();
- if (is_animating())
- Stop();
- view_.reset();
+ break;
+ case ui::ET_GESTURE_LONG_PRESS:
+ if (is_animating())
+ End();
+ // fall through to default to reset the view and tap down target.
+ default:
+ // On all other touch and gesture events, we hide the animation.
+ StopAnimation();
+ break;
}
+}
- // Overridden from ui::LinearAnimation.
- virtual void AnimateToState(double state) OVERRIDE {
- DCHECK(view_.get());
- view_->UpdateWithAnimation(this);
- }
+void LongPressAffordanceAnimation::StartAnimation() {
+ view_.reset(new LongPressAffordanceView(tap_down_location_));
+ Start();
+}
- // Overridden from ui::AnimationDelegate.
- virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE {
- view_.reset();
- }
+void LongPressAffordanceAnimation::StopAnimation() {
+ if (timer_.IsRunning())
+ timer_.Stop();
+ if (is_animating())
+ Stop();
+ view_.reset();
+ tap_down_target_ = NULL;
+}
- virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE {
- }
+void LongPressAffordanceAnimation::AnimateToState(double state) {
+ DCHECK(view_.get());
+ view_->UpdateWithAnimation(this);
+}
- virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE {
- view_.reset();
- }
+void LongPressAffordanceAnimation::AnimationEnded(
+ const ui::Animation* animation) {
+ view_.reset();
+ tap_down_target_ = NULL;
+}
- scoped_ptr<LongPressAffordanceView> view_;
- gfx::Point tap_down_location_;
- base::OneShotTimer<LongPressAffordanceAnimation> timer_;
+void LongPressAffordanceAnimation::AnimationProgressed(
+ const ui::Animation* animation) {
+}
- DISALLOW_COPY_AND_ASSIGN(LongPressAffordanceAnimation);
-};
+void LongPressAffordanceAnimation::AnimationCanceled(
+ const ui::Animation* animation) {
+ view_.reset();
+ tap_down_target_ = NULL;
+}
class SystemPinchHandler {
public:
diff --git a/ash/wm/system_gesture_event_filter.h b/ash/wm/system_gesture_event_filter.h
index 3c258d7..9389c2f 100644
--- a/ash/wm/system_gesture_event_filter.h
+++ b/ash/wm/system_gesture_event_filter.h
@@ -8,18 +8,28 @@
#include "ash/shell.h"
#include "ash/touch/touch_uma.h"
+#include "base/timer.h"
#include "ui/aura/event_filter.h"
#include "ui/aura/window_observer.h"
+#include "ui/base/animation/animation_delegate.h"
+#include "ui/base/animation/linear_animation.h"
+#include "ui/gfx/point.h"
#include <map>
namespace aura {
-class MouseEvent;
class KeyEvent;
+class LocatedEvent;
+class MouseEvent;
class Window;
}
namespace ash {
+
+namespace test {
+class SystemGestureEventFilterTest;
+} // namespace test
+
namespace internal {
class SystemPinchHandler;
@@ -39,6 +49,41 @@ enum ScrollOrientation {
SCROLL_ORIENTATION_VERTICAL
};
+// LongPressAffordanceAnimation displays an animated affordance that is shown
+// on a TAP_DOWN gesture. The animation completes on a LONG_PRESS gesture, or is
+// canceled and hidden if any other event is received before that.
+class LongPressAffordanceAnimation : public ui::AnimationDelegate,
+ public ui::LinearAnimation {
+ public:
+ LongPressAffordanceAnimation();
+ virtual ~LongPressAffordanceAnimation();
+
+ // Display or removes long press affordance according to the |event|.
+ void ProcessEvent(aura::Window* target, aura::LocatedEvent* event);
+
+ private:
+ friend class ash::test::SystemGestureEventFilterTest;
+
+ void StartAnimation();
+ void StopAnimation();
+
+ // Overridden from ui::LinearAnimation.
+ virtual void AnimateToState(double state) OVERRIDE;
+
+ // Overridden from ui::AnimationDelegate.
+ virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
+ virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
+ virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE;
+
+ class LongPressAffordanceView;
+ scoped_ptr<LongPressAffordanceView> view_;
+ gfx::Point tap_down_location_;
+ aura::Window* tap_down_target_;
+ base::OneShotTimer<LongPressAffordanceAnimation> timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(LongPressAffordanceAnimation);
+};
+
// An event filter which handles system level gesture events.
class SystemGestureEventFilter : public aura::EventFilter,
public aura::WindowObserver {
@@ -63,6 +108,8 @@ class SystemGestureEventFilter : public aura::EventFilter,
virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
private:
+ friend class ash::test::SystemGestureEventFilterTest;
+
// Removes system-gesture handlers for a window.
void ClearGestureHandlerForWindow(aura::Window* window);
@@ -96,7 +143,6 @@ class SystemGestureEventFilter : public aura::EventFilter,
// A device swipe gesture is in progress.
bool is_scrubbing_;
- class LongPressAffordanceAnimation;
scoped_ptr<LongPressAffordanceAnimation> long_press_affordance_;
TouchUMA touch_uma_;
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc
index 2ca46bf..8f0fceb 100644
--- a/ash/wm/system_gesture_event_filter_unittest.cc
+++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -4,6 +4,7 @@
#include "ash/wm/system_gesture_event_filter.h"
+#include "base/timer.h"
#include "ash/accelerators/accelerator_controller.h"
#include "ash/launcher/launcher.h"
#include "ash/launcher/launcher_model.h"
@@ -95,7 +96,34 @@ class DummyBrightnessControlDelegate : public BrightnessControlDelegate,
} // namespace
-typedef test::AshTestBase SystemGestureEventFilterTest;
+class SystemGestureEventFilterTest : public AshTestBase {
+ public:
+ SystemGestureEventFilterTest() : AshTestBase() {}
+ virtual ~SystemGestureEventFilterTest() {}
+
+ internal::LongPressAffordanceAnimation* GetLongPressAffordance() {
+ Shell::TestApi shell_test(Shell::GetInstance());
+ return shell_test.system_gesture_event_filter()->
+ long_press_affordance_.get();
+ }
+
+ base::OneShotTimer<internal::LongPressAffordanceAnimation>*
+ GetLongPressAffordanceTimer() {
+ return &GetLongPressAffordance()->timer_;
+ }
+
+ aura::Window* GetLongPressAffordanceTarget() {
+ return GetLongPressAffordance()->tap_down_target_;
+ }
+
+ views::View* GetLongPressAffordanceView() {
+ return reinterpret_cast<views::View*>(
+ GetLongPressAffordance()->view_.get());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SystemGestureEventFilterTest);
+};
// Ensure that events targeted at the root window are consumed by the
// system event handler.
@@ -341,5 +369,56 @@ TEST_F(SystemGestureEventFilterTest, ApplicationControl) {
}
}
+TEST_F(SystemGestureEventFilterTest, LongPressAffordanceStateOnCaptureLoss) {
+ aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+
+ aura::test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> window0(
+ aura::test::CreateTestWindowWithDelegate(
+ &delegate, 9, gfx::Rect(0, 0, 100, 100), root_window));
+ scoped_ptr<aura::Window> window1(
+ aura::test::CreateTestWindowWithDelegate(
+ &delegate, 10, gfx::Rect(0, 0, 100, 50), window0.get()));
+ scoped_ptr<aura::Window> window2(
+ aura::test::CreateTestWindowWithDelegate(
+ &delegate, 11, gfx::Rect(0, 50, 100, 50), window0.get()));
+
+ const int kTouchId = 5;
+
+ // Capture first window.
+ window1->SetCapture();
+ EXPECT_TRUE(window1->HasCapture());
+
+ // Send touch event to first window.
+ aura::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId,
+ base::Time::NowFromSystemTime() - base::Time());
+ root_window->DispatchTouchEvent(&press);
+ EXPECT_TRUE(window1->HasCapture());
+
+ base::OneShotTimer<internal::LongPressAffordanceAnimation>* timer =
+ GetLongPressAffordanceTimer();
+ EXPECT_TRUE(timer->IsRunning());
+ EXPECT_EQ(window1.get(), GetLongPressAffordanceTarget());
+
+ // Force timeout so that the affordance animation can start.
+ timer->user_task().Run();
+ timer->Stop();
+ EXPECT_TRUE(GetLongPressAffordance()->is_animating());
+
+ // Change capture.
+ window2->SetCapture();
+ EXPECT_TRUE(window2->HasCapture());
+
+ EXPECT_TRUE(GetLongPressAffordance()->is_animating());
+ EXPECT_EQ(window1.get(), GetLongPressAffordanceTarget());
+
+ // Animate to completion.
+ GetLongPressAffordance()->End();
+
+ // Check if state has reset.
+ EXPECT_EQ(NULL, GetLongPressAffordanceTarget());
+ EXPECT_EQ(NULL, GetLongPressAffordanceView());
+}
+
} // namespace test
} // namespace ash