blob: b4195b4ad091cfdef39bde303048fb0045075785 [file] [log] [blame]
// Copyright 2016 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/ash_export.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/tick_clock.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "ui/events/event.h"
#include "ui/events/event_handler.h"
#include "ui/events/gesture_detection/gesture_detector.h"
namespace aura {
class Window;
namespace ash {
// A delegate to handle commands in response to detected accessibility gesture
// events.
class TouchAccessibilityEnablerDelegate {
virtual ~TouchAccessibilityEnablerDelegate() {}
// Called when we first detect two fingers are held down.
virtual void OnTwoFingerTouchStart() {}
// Called when the user is no longer holding down two fingers (including
// releasing one, holding down three, or moving them).
virtual void OnTwoFingerTouchStop() {}
// While the user holds down two fingers on a touch screen, which is the
// gesture to enable spoken feedback (if held down long enough), play a sound
// every "tick" (approximately every half-second) to warn the user something
// is about to happen.
virtual void PlaySpokenFeedbackToggleCountdown(int tick_count) {}
// Toggles spoken feedback.
virtual void ToggleSpokenFeedback() {}
// TouchAccessibilityEnabler triggers turning spoken feedback on or off
// by holding down two fingers on the touch screen for several seconds.
class ASH_EXPORT TouchAccessibilityEnabler : public ui::EventHandler {
TouchAccessibilityEnabler(aura::Window* root_window,
TouchAccessibilityEnablerDelegate* delegate);
~TouchAccessibilityEnabler() override;
bool IsInNoFingersDownForTesting() { return state_ == NO_FINGERS_DOWN; }
bool IsInOneFingerDownForTesting() { return state_ == ONE_FINGER_DOWN; }
bool IsInTwoFingersDownForTesting() { return state_ == TWO_FINGERS_DOWN; }
bool IsInWaitForNoFingersForTesting() {
return state_ == WAIT_FOR_NO_FINGERS;
void TriggerOnTimerForTesting() { OnTimer(); }
// When TouchExplorationController is running, it tells this class to
// remove its event handler so that it can pass it the unrewritten events
// directly. Otherwise, this class would only receive the rewritten events,
// which would require entirely separate logic.
void RemoveEventHandler();
void AddEventHandler();
void HandleTouchEvent(const ui::TouchEvent& event);
// Expose a weak ptr so that TouchExplorationController can hold a reference
// to this object without worrying about destruction order during shutdown.
base::WeakPtr<TouchAccessibilityEnabler> GetWeakPtr();
// Overridden from ui::EventHandler
void OnTouchEvent(ui::TouchEvent* event) override;
void StartTimer();
void CancelTimer();
void OnTimer();
void ResetToNoFingersDown();
// Returns the current time of the tick clock.
base::TimeTicks Now();
enum State {
// No fingers are down.
// One finger is down and it's possible this could be a two-finger-hold.
// Two fingers are down and stationary and we will trigger enabling
// spoken feedback after a delay.
// This is the "reject" state when we get anything other than two fingers
// held down and stationary. Stay in this state until all fingers are
// removed.
aura::Window* root_window_;
// Called when we detect a long-press of two fingers. Not owned.
TouchAccessibilityEnablerDelegate* delegate_;
// The current state.
State state_;
// The time when we entered the two finger state.
base::TimeTicks two_finger_start_time_;
// Map of touch ids to their initial locations.
std::map<int, gfx::PointF> touch_locations_;
// A timer that triggers repeatedly while two fingers are held down.
base::RepeatingTimer timer_;
// A default gesture detector config, so we can share the same
// timeout and pixel slop constants.
ui::GestureDetector::Config gesture_detector_config_;
// When touch_accessibility_enabler gets time relative to real time during
// testing, this clock is set to the simulated clock and used.
const base::TickClock* tick_clock_;
// Whether or not we currently have an event handler installed. It can
// be removed when TouchExplorationController is running.
bool event_handler_installed_ = false;
base::WeakPtrFactory<TouchAccessibilityEnabler> weak_factory_;
} // namespace ash