Commit 217ba203 authored by lisayin@chromium.org's avatar lisayin@chromium.org

Swipe Gestures for Accessibility

Register that gestures have been received by the touch_exploration_controller in Accessibility Mode.

Swipe gestures are registered when the user begins a swipe and completes it before the time out period. If a swipe is successfully completed, the keyboard shortcut <shift>+<search>+direction will called. 

If the grace period has elapsed, then the mode changes to touch exploration. If an additional finger has been added before the grace period has elapsed, then the mode changes to passthrough.

BUG= 387304

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=281614

Review URL: https://codereview.chromium.org/330763007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@281780 0039d316-1c4b-4281-b951-d872f2087c98
parent bd046386
......@@ -7,6 +7,8 @@
#include "ash/accessibility_delegate.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
......@@ -16,13 +18,18 @@
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/test_event_handler.h"
namespace ui {
class TouchExplorationTest : public InProcessBrowserTest {
public:
TouchExplorationTest() {}
TouchExplorationTest() : simulated_clock_(new base::SimpleTestTickClock()) {
// Tests fail if time is ever 0.
simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10));
}
virtual ~TouchExplorationTest() {}
protected:
......@@ -33,6 +40,14 @@ class TouchExplorationTest : public InProcessBrowserTest {
ad->ToggleSpokenFeedback(ash::A11Y_NOTIFICATION_NONE);
}
base::TimeDelta Now() {
return base::TimeDelta::FromInternalValue(
simulated_clock_->NowTicks().ToInternalValue());
}
ui::GestureDetector::Config gesture_detector_config_;
base::SimpleTestTickClock* simulated_clock_;
private:
DISALLOW_COPY_AND_ASSIGN(TouchExplorationTest);
};
......@@ -57,13 +72,26 @@ IN_PROC_BROWSER_TEST_F(TouchExplorationTest, ToggleOnOff) {
SwitchTouchExplorationMode(true);
aura::test::EventGenerator generator(root_window);
generator.set_current_location(gfx::Point(100, 200));
generator.PressTouchId(1);
base::TimeDelta initial_time = Now();
ui::TouchEvent initial_press(
ui::ET_TOUCH_PRESSED, gfx::Point(100, 200), 1, initial_time);
float delta_time =
(initial_press.location() - gfx::Point(109,209)).Length() /
gesture_detector_config_.minimum_swipe_velocity;
ui::TouchEvent touch_move(
ui::ET_TOUCH_MOVED,
gfx::Point(109, 209),
1,
initial_time + base::TimeDelta::FromSecondsD(delta_time));
generator.Dispatch(&initial_press);
// Since the touch exploration controller doesn't know if the user is
// double-tapping or not, touch exploration is only initiated if the
// user moves more than 8 pixels away from the initial location (the "slop"),
// or after 300 ms has elapsed.
generator.MoveTouchId(gfx::Point(109, 209), 1);
// or after 300 ms has elapsed if the finger does not move fast enough.
generator.Dispatch(&touch_move);
// Number of mouse events may be greater than 1 because of ET_MOUSE_ENTERED.
EXPECT_GT(event_handler->num_mouse_events(), 0);
EXPECT_EQ(0, event_handler->num_touch_events());
......@@ -76,9 +104,20 @@ IN_PROC_BROWSER_TEST_F(TouchExplorationTest, ToggleOnOff) {
event_handler->Reset();
SwitchTouchExplorationMode(true);
generator.set_current_location(gfx::Point(500, 600));
generator.PressTouchId(2);
generator.MoveTouchId(gfx::Point(509, 609), 2);
initial_time = Now();
ui::TouchEvent second_initial_press(
ui::ET_TOUCH_PRESSED, gfx::Point(500, 600), 2, initial_time);
delta_time =
(second_initial_press.location() - gfx::Point(509, 609)).Length() /
gesture_detector_config_.minimum_swipe_velocity;
ui::TouchEvent second_move(
ui::ET_TOUCH_MOVED,
gfx::Point(509, 609),
2,
initial_time + base::TimeDelta::FromSecondsD(delta_time));
generator.Dispatch(&second_initial_press);
generator.Dispatch(&second_move);
EXPECT_GT(event_handler->num_mouse_events(), 0);
EXPECT_EQ(0, event_handler->num_touch_events());
......
This diff is collapsed.
......@@ -11,6 +11,7 @@
#include "ui/events/event.h"
#include "ui/events/event_rewriter.h"
#include "ui/events/gesture_detection/gesture_detector.h"
#include "ui/events/gestures/gesture_provider_aura.h"
#include "ui/gfx/geometry/point.h"
namespace aura {
......@@ -21,10 +22,13 @@ namespace ui {
class Event;
class EventHandler;
class GestureEvent;
class GestureProviderAura;
class TouchEvent;
// TouchExplorationController is used in tandem with "Spoken Feedback" to
// make the touch UI accessible.
// make the touch UI accessible. Gestures are mapped to accessiblity key
// shortcuts.
//
// ** Short version **
//
......@@ -32,7 +36,8 @@ class TouchEvent;
// exploring the screen gets turned into mouse moves (which can then be
// spoken by an accessibility service running), a single tap while the user
// is in touch exploration or a double-tap simulates a click, and gestures
// can be used to send high-level accessibility commands.
// can be used to send high-level accessibility commands. For example, a swipe
// right would correspond to the keyboard short cut shift+search+right.
// When two or more fingers are pressed initially, from then on the events
// are passed through, but with the initial finger removed - so if you swipe
// down with two fingers, the running app will see a one-finger swipe.
......@@ -61,6 +66,14 @@ class TouchEvent;
// location. This allows the user to perform a single tap
// anywhere to activate it.
//
// The user can perform swipe gestures in one of the four cardinal directions
// which will be interpreted and used to control the UI. The gesture will only
// be registered if the finger moves outside the slop and completed within the
// grace period. If additional fingers are added during the grace period, the
// state changes to passthrough. If the gesture fails to be completed within the
// grace period, the state changes to touch exploration mode. Once the state has
// changed, any gestures made during the grace period are discarded.
//
// If the user double-taps, the second tap is passed through, allowing the
// user to click - however, the double-tap location is changed to the location
// of the last successful touch exploration - that allows the user to explore
......@@ -84,7 +97,8 @@ class TouchEvent;
// The caller is expected to retain ownership of instances of this class and
// destroy them before |root_window| is destroyed.
class UI_CHROMEOS_EXPORT TouchExplorationController
: public ui::EventRewriter {
: public ui::EventRewriter,
public ui::GestureProviderAuraClient {
public:
explicit TouchExplorationController(aura::Window* root_window);
virtual ~TouchExplorationController();
......@@ -92,6 +106,7 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
void CallTapTimerNowForTesting();
void SetEventHandlerForTesting(ui::EventHandler* event_handler_for_testing);
bool IsInNoFingersDownStateForTesting() const;
bool IsInGestureInProgressStateForTesting() const;
private:
// Overridden from ui::EventRewriter
......@@ -116,6 +131,8 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
ui::EventRewriteStatus InPassthrough(
const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
ui::EventRewriteStatus InGestureInProgress(
const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
ui::EventRewriteStatus InTouchExploreSecondPress(
const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
ui::EventRewriteStatus InWaitForRelease(
......@@ -130,6 +147,23 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
// Dispatch a new event outside of the event rewriting flow.
void DispatchEvent(ui::Event* event);
// Overridden from GestureProviderAuraClient.
//
// The gesture provider keeps track of all the touch events after
// the user moves fast enough to trigger a gesture. After the user
// completes their gesture, this method will decide what keyboard
// input their gesture corresponded to.
virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE;
// Process the gesture events that have been created.
void ProcessGestureEvents();
void OnSwipeEvent(ui::GestureEvent* swipe_gesture);
// Dispatches the keyboard short cut Shift+Search+<arrow key>
// outside the event rewritting flow.
void DispatchShiftSearchKeyEvent(const ui::KeyboardCode direction);
scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location,
int flags);
......@@ -172,6 +206,15 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
// mode until all fingers are lifted.
TOUCH_EXPLORATION,
// If the user moves their finger faster than the threshold velocity after a
// single tap, the touch events that follow will be translated into gesture
// events. If the user successfully completes a gesture within the grace
// period, the gesture will be interpreted and used to control the UI via
// discrete actions - currently by synthesizing key events corresponding to
// each gesture Otherwise, the collected gestures are discarded and the
// state changes to touch_exploration.
GESTURE_IN_PROGRESS,
// The user was in touch exploration, but has placed down another finger.
// If the user releases the second finger, a touch press and release
// will go through at the last touch explore location. If the user
......@@ -244,6 +287,9 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
// timeout and pixel slop constants.
ui::GestureDetector::Config gesture_detector_config_;
// Gesture Handler to interpret the touch events.
ui::GestureProviderAura gesture_provider_;
// The previous state entered.
State prev_state_;
......
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