Commit 7d487599 authored by lisayin@chromium.org's avatar lisayin@chromium.org

Added side slide gestures to touch exploration controller.

The user can control settings that might be normally changed using sliders by sliding along the edge of the screen when ChromeVox is on. For example, the user can slide along the right edge of the screen and adjust the volume.

If the user enters this mode and leaves the boundaries without releasing their touch, they will stop adjusting the setting, however, they will not enter touch exploration. If they return to the given boundaries, they will be able to modify the setting again. If the user does not touch a "hot edge" of the screen, they will not enter this state if they move to the an of the screen. 

BUG=393326

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

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285149 0039d316-1c4b-4281-b951-d872f2087c98
parent 518c63a8
......@@ -42,6 +42,8 @@
'ash_constants.h',
'ash_switches.cc',
'ash_switches.h',
'ash_touch_exploration_manager_chromeos.cc',
'ash_touch_exploration_manager_chromeos.h',
'cancel_mode.cc',
'cancel_mode.h',
'debug.cc',
......@@ -753,6 +755,7 @@
'accelerators/accelerator_table_unittest.cc',
'accelerators/magnifier_key_scroller_unittest.cc',
'accelerators/spoken_feedback_toggler_unittest.cc',
'ash_touch_exploration_manager_chromeos_unittest.cc',
'autoclick/autoclick_unittest.cc',
'desktop_background/desktop_background_controller_unittest.cc',
'desktop_background/wallpaper_resizer_unittest.cc',
......
// 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/ash_touch_exploration_manager_chromeos.h"
#include "ash/accessibility_delegate.h"
#include "ash/audio/sounds.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "base/command_line.h"
#include "chromeos/audio/chromeos_sounds.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "chromeos/chromeos_switches.h"
#include "ui/chromeos/touch_exploration_controller.h"
namespace ash {
AshTouchExplorationManager::AshTouchExplorationManager(
RootWindowController* root_window_controller)
: root_window_controller_(root_window_controller),
audio_handler_(chromeos::CrasAudioHandler::Get()) {
Shell::GetInstance()->system_tray_notifier()->AddAccessibilityObserver(this);
UpdateTouchExplorationState();
}
AshTouchExplorationManager::~AshTouchExplorationManager() {
SystemTrayNotifier* system_tray_notifier =
Shell::GetInstance()->system_tray_notifier();
if (system_tray_notifier)
system_tray_notifier->RemoveAccessibilityObserver(this);
}
void AshTouchExplorationManager::OnAccessibilityModeChanged(
AccessibilityNotificationVisibility notify) {
UpdateTouchExplorationState();
}
void AshTouchExplorationManager::PlayVolumeAdjustSound() {
if (!VolumeAdjustSoundEnabled())
return;
if ((!audio_handler_->IsOutputMuted()) ||
!(audio_handler_->GetOutputVolumePercent() == 100))
PlaySystemSoundIfSpokenFeedback(chromeos::SOUND_VOLUME_ADJUST);
}
void AshTouchExplorationManager::SetOutputLevel(int volume) {
if (volume > 0) {
if (audio_handler_->IsOutputMuted()) {
audio_handler_->SetOutputMute(false);
}
}
audio_handler_->SetOutputVolumePercent(volume);
// Avoid negative volume.
if (audio_handler_->IsOutputVolumeBelowDefaultMuteLevel())
audio_handler_->SetOutputMute(true);
}
void AshTouchExplorationManager::UpdateTouchExplorationState() {
AccessibilityDelegate* delegate =
Shell::GetInstance()->accessibility_delegate();
bool enabled = delegate->IsSpokenFeedbackEnabled();
if (enabled && !touch_exploration_controller_.get()) {
touch_exploration_controller_.reset(new ui::TouchExplorationController(
root_window_controller_->GetRootWindow(), this));
} else if (!enabled) {
touch_exploration_controller_.reset();
}
}
bool AshTouchExplorationManager::VolumeAdjustSoundEnabled() {
return !CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kDisableVolumeAdjustSound);
}
} // namespace ash
// 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_TOUCH_EXPLORATION_MANAGER_CHROMEOS_H_
#define ASH_TOUCH_EXPLORATION_MANAGER_CHROMEOS_H_
#include "ash/ash_export.h"
#include "ash/system/tray_accessibility.h"
#include "ui/chromeos/touch_exploration_controller.h"
namespace chromeos {
class CrasAudioHandler;
}
namespace ash {
class RootWindowController;
// Responsible for initializing TouchExplorationController when spoken
// feedback is on for ChromeOS only. This class implements
// TouchExplorationControllerDelegate which allows touch gestures to manipulate
// the system.
class ASH_EXPORT AshTouchExplorationManager
: public ash::AccessibilityObserver,
public ui::TouchExplorationControllerDelegate {
public:
explicit AshTouchExplorationManager(
RootWindowController* root_window_controller);
virtual ~AshTouchExplorationManager();
// AccessibilityObserver overrides:
virtual void OnAccessibilityModeChanged(
AccessibilityNotificationVisibility notify) OVERRIDE;
// TouchExplorationControllerDelegate overrides:
virtual void PlayVolumeAdjustSound() OVERRIDE;
virtual void SetOutputLevel(int volume) OVERRIDE;
private:
void UpdateTouchExplorationState();
bool VolumeAdjustSoundEnabled();
scoped_ptr<ui::TouchExplorationController> touch_exploration_controller_;
RootWindowController* root_window_controller_;
chromeos::CrasAudioHandler* audio_handler_;
DISALLOW_COPY_AND_ASSIGN(AshTouchExplorationManager);
};
} // namespace ash
#endif // ASH_TOUCH_EXPLORATION_MANAGER_CHROMEOS_H_
// 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/ash_touch_exploration_manager_chromeos.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "chromeos/audio/cras_audio_handler.h"
namespace ash {
typedef test::AshTestBase AshTouchExplorationManagerTest;
TEST_F(AshTouchExplorationManagerTest, AdjustSound) {
RootWindowController* controller = Shell::GetPrimaryRootWindowController();
AshTouchExplorationManager touch_exploration_manager(controller);
chromeos::CrasAudioHandler* audio_handler =
chromeos::CrasAudioHandler::Get();
touch_exploration_manager.SetOutputLevel(10);
EXPECT_EQ(audio_handler->GetOutputVolumePercent(), 10);
EXPECT_FALSE(audio_handler->IsOutputMuted());
touch_exploration_manager.SetOutputLevel(100);
EXPECT_EQ(audio_handler->GetOutputVolumePercent(), 100);
EXPECT_FALSE(audio_handler->IsOutputMuted());
touch_exploration_manager.SetOutputLevel(0);
EXPECT_EQ(audio_handler->GetOutputVolumePercent(), 0);
EXPECT_TRUE(audio_handler->IsOutputMuted());
touch_exploration_manager.SetOutputLevel(-10);
EXPECT_EQ(audio_handler->GetOutputVolumePercent(), 0);
EXPECT_TRUE(audio_handler->IsOutputMuted());
}
} // namespace ash
......@@ -76,7 +76,7 @@
#include "ui/wm/public/window_types.h"
#if defined(OS_CHROMEOS)
#include "ash/system/tray_accessibility.h"
#include "ash/ash_touch_exploration_manager_chromeos.h"
#include "ash/wm/boot_splash_screen_chromeos.h"
#include "ui/chromeos/touch_exploration_controller.h"
#endif
......@@ -261,54 +261,6 @@ class EmptyWindowDelegate : public aura::WindowDelegate {
DISALLOW_COPY_AND_ASSIGN(EmptyWindowDelegate);
};
#if defined(OS_CHROMEOS)
// Responsible for initializing TouchExplorationController when spoken
// feedback is on.
class CrosAccessibilityObserver : public AccessibilityObserver {
public:
explicit CrosAccessibilityObserver(
RootWindowController* root_window_controller)
: root_window_controller_(root_window_controller) {
Shell::GetInstance()->system_tray_notifier()->
AddAccessibilityObserver(this);
UpdateTouchExplorationState();
}
virtual ~CrosAccessibilityObserver() {
SystemTrayNotifier* system_tray_notifier =
Shell::GetInstance()->system_tray_notifier();
if (system_tray_notifier)
system_tray_notifier->RemoveAccessibilityObserver(this);
}
private:
void UpdateTouchExplorationState() {
AccessibilityDelegate* delegate =
Shell::GetInstance()->accessibility_delegate();
bool enabled = delegate->IsSpokenFeedbackEnabled();
if (enabled && !touch_exploration_controller_.get()) {
touch_exploration_controller_.reset(
new ui::TouchExplorationController(
root_window_controller_->GetRootWindow()));
} else if (!enabled) {
touch_exploration_controller_.reset();
}
}
// Overridden from AccessibilityObserver.
virtual void OnAccessibilityModeChanged(
AccessibilityNotificationVisibility notify) OVERRIDE {
UpdateTouchExplorationState();
}
scoped_ptr<ui::TouchExplorationController> touch_exploration_controller_;
RootWindowController* root_window_controller_;
DISALLOW_COPY_AND_ASSIGN(CrosAccessibilityObserver);
};
#endif // OS_CHROMEOS
} // namespace
void RootWindowController::CreateForPrimaryDisplay(AshWindowTreeHost* host) {
......@@ -396,8 +348,8 @@ void RootWindowController::Shutdown() {
shell->RemoveShellObserver(this);
#if defined(OS_CHROMEOS)
if (cros_accessibility_observer_) {
cros_accessibility_observer_.reset();
if (touch_exploration_manager_) {
touch_exploration_manager_.reset();
}
#endif
......@@ -807,7 +759,7 @@ void RootWindowController::Init(RootWindowType root_window_type,
#if defined(OS_CHROMEOS)
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kAshDisableTouchExplorationMode)) {
cros_accessibility_observer_.reset(new CrosAccessibilityObserver(this));
touch_exploration_manager_.reset(new AshTouchExplorationManager(this));
}
#endif
}
......
......@@ -68,7 +68,7 @@ class WorkspaceController;
#if defined(OS_CHROMEOS)
class BootSplashScreen;
class AccessibilityObserver;
class AshTouchExplorationManager;
#endif
// This class maintains the per root window state for ash. This class
......@@ -298,7 +298,7 @@ class ASH_EXPORT RootWindowController : public ShellObserver {
scoped_ptr<BootSplashScreen> boot_splash_screen_;
// Responsible for initializing TouchExplorationController when spoken
// feedback is on.
scoped_ptr<AccessibilityObserver> cros_accessibility_observer_;
scoped_ptr<AshTouchExplorationManager> touch_exploration_manager_;
#endif
scoped_ptr<ScreenDimmer> screen_dimmer_;
......
......@@ -67,7 +67,7 @@ bool VolumeController::HandleVolumeDown(const ui::Accelerator& accelerator) {
audio_handler->SetOutputVolumePercent(0);
} else {
audio_handler->AdjustOutputVolumeByPercent(-kStepPercentage);
if (audio_handler->IsOutputVolumeBelowDefaultMuteLvel())
if (audio_handler->IsOutputVolumeBelowDefaultMuteLevel())
audio_handler->SetOutputMute(true);
else
PlayVolumeAdjustSound();
......
......@@ -116,7 +116,7 @@ bool CrasAudioHandler::IsOutputMutedForDevice(uint64 device_id) {
return audio_pref_handler_->GetMuteValue(*device);
}
bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLvel() {
bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLevel() {
return output_volume_ <= kMuteThresholdPercent;
}
......
......@@ -97,7 +97,7 @@ class CHROMEOS_EXPORT CrasAudioHandler : public CrasAudioClient::Observer,
virtual bool IsInputMutedForDevice(uint64 device_id);
// Returns true if the output volume is below the default mute volume level.
virtual bool IsOutputVolumeBelowDefaultMuteLvel();
virtual bool IsOutputVolumeBelowDefaultMuteLevel();
// Returns volume level in 0-100% range at which the volume should be muted.
virtual int GetOutputDefaultVolumeMuteThreshold();
......
This diff is collapsed.
......@@ -26,9 +26,25 @@ class GestureEvent;
class GestureProviderAura;
class TouchEvent;
// A delegate to handle commands in response to detected accessibility gesture
// events.
class TouchExplorationControllerDelegate {
public:
virtual ~TouchExplorationControllerDelegate() {}
// This function should be called whenever the delegate wants to play a sound
// when the volume adjusts.
virtual void PlayVolumeAdjustSound() = 0;
// Takes an int from 0.0 to 100.0 that indicates the percent the volume
// should be set to.
virtual void SetOutputLevel(int volume) = 0;
};
// TouchExplorationController is used in tandem with "Spoken Feedback" to
// make the touch UI accessible. Gestures are mapped to accessiblity key
// shortcuts.
// make the touch UI accessible. Gestures performed in the middle of the screen
// are mapped to accessiblity key shortcuts while gestures performed on the edge
// of the screen can change settings.
//
// ** Short version **
//
......@@ -40,7 +56,10 @@ class TouchEvent;
// 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.
// down with two fingers, the running app will see a one-finger swipe. Slide
// gestures performed on the edge of the screen can change settings
// continuously. For example, sliding a finger along the right side of the
// screen will change the volume.
//
// ** Long version **
//
......@@ -91,6 +110,24 @@ class TouchEvent;
// adds a third finger while in two to one finger mode, all fingers and touch
// events are passed through from then on.
//
// If the user places a finger on the edge of the screen and moves their finger
// past slop, a slide gesture is performed. The user can then slide one finger
// along an edge of the screen and continuously control a setting. Once the user
// enters this state, the boundaries that define an edge expand so that the user
// can now adjust the setting within a slightly bigger width along the screen.
// If the user exits this area without lifting their finger, they will not be
// able to perform any actions, however if they keep their finger down and
// return to the "hot edge," then they can still adjust the setting. In order to
// perform other touch accessibility movements, the user must lift their finger.
// If additional fingers are added while in this state, the user will transition
// to passthrough.
//
// Currently, only the right edge is mapped to control the volume. Volume
// control along the edge of the screen is directly proportional to where the
// user's finger is located on the screen. The top right corner of the screen
// automatically sets the volume to 100% and the bottome right corner of the
// screen automatically sets the volume to 0% once the user has moved past slop.
//
// Once touch exploration mode has been activated,
// it remains in that mode until all fingers have been released.
//
......@@ -100,7 +137,9 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
: public ui::EventRewriter,
public ui::GestureProviderAuraClient {
public:
explicit TouchExplorationController(aura::Window* root_window);
explicit TouchExplorationController(
aura::Window* root_window,
ui::TouchExplorationControllerDelegate* delegate);
virtual ~TouchExplorationController();
private:
......@@ -134,6 +173,8 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
ui::EventRewriteStatus InWaitForRelease(
const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
ui::EventRewriteStatus InSlideGesture(
const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
// This timer is started every time we get the first press event, and
// it fires after the double-click timeout elapses (300 ms by default).
......@@ -157,6 +198,8 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
void OnSwipeEvent(ui::GestureEvent* swipe_gesture);
void SideSlideControl(ui::GestureEvent* gesture);
// Dispatches the keyboard short cut Shift+Search+<arrow key>
// outside the event rewritting flow.
void DispatchShiftSearchKeyEvent(const ui::KeyboardCode direction);
......@@ -170,6 +213,22 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
// default value.
void ResetToNoFingersDown();
void PlaySoundForTimer();
// Some constants used in touch_exploration_controller:
// Within this many dips of the screen edge, the release event generated will
// reset the state to NoFingersDown.
const float kLeavingScreenEdge = 6;
// Swipe/scroll gestures within these bounds (in DIPs) will change preset
// settings.
const float kMaxDistanceFromEdge = 75;
// After a slide gesture has been triggered, if the finger is still within
// these bounds (in DIPs), the preset settings will still change.
const float kSlopDistanceFromEdge = kMaxDistanceFromEdge + 40;
enum State {
// No fingers are down and no events are pending.
NO_FINGERS_DOWN,
......@@ -236,8 +295,28 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
// generally useful for developing new features, because it creates a
// simple way to handle a dead end in user flow.
WAIT_FOR_RELEASE,
// If the user is within the given bounds from an edge of the screen, not
// including corners, then the resulting movements will be interpreted as
// slide gestures.
SLIDE_GESTURE,
};
enum ScreenLocation {
// Hot "edges" of the screen are each represented by a respective bit.
NO_EDGE = 0,
RIGHT_EDGE = 1 << 0,
TOP_EDGE = 1 << 1,
LEFT_EDGE = 1 << 2,
BOTTOM_EDGE = 1 << 3,
};
// Given a point, if it is within the given bounds of an edge, returns the
// edge. If it is within the given bounds of two edges, returns an int with
// both bits that represent the respective edges turned on. Otherwise returns
// SCREEN_CENTER.
int FindEdgesWithinBounds(gfx::Point point, float bounds);
void VlogState(const char* function_name);
void VlogEvent(const ui::TouchEvent& event, const char* function_name);
......@@ -247,6 +326,9 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
aura::Window* root_window_;
// Handles volume control. Not owned.
ui::TouchExplorationControllerDelegate* delegate_;
// A set of touch ids for fingers currently touching the screen.
std::vector<int> current_touch_ids_;
......@@ -276,6 +358,9 @@ class UI_CHROMEOS_EXPORT TouchExplorationController
// A timer to fire the mouse move event after the double-tap delay.
base::OneShotTimer<TouchExplorationController> tap_timer_;
// A timer to fire an indicating sound when sliding to change volume.
base::RepeatingTimer<TouchExplorationController> sound_timer_;
// For testing only, an event handler to use for generated events
// outside of the normal event rewriting flow.
ui::EventHandler* event_handler_for_testing_;
......
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