Commit 6792dc8a authored by David Tseng's avatar David Tseng Committed by Commit Bot

Reland: Initial support for Spoken Feedback tablet toggle

TBR=derat@chromium.org

Change-Id: I5b31bee43dfca9de4d4aa188642a1f1ff9cfbca5
Reviewed-on: https://chromium-review.googlesource.com/1044289Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Commit-Queue: David Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556145}
parent acfc35c6
...@@ -71,6 +71,10 @@ component("ash") { ...@@ -71,6 +71,10 @@ component("ash") {
"accessibility/focus_ring_controller.h", "accessibility/focus_ring_controller.h",
"accessibility/focus_ring_layer.cc", "accessibility/focus_ring_layer.cc",
"accessibility/focus_ring_layer.h", "accessibility/focus_ring_layer.h",
"accessibility/key_accessibility_enabler.cc",
"accessibility/key_accessibility_enabler.h",
"accessibility/spoken_feedback_enabler.cc",
"accessibility/spoken_feedback_enabler.h",
"accessibility/touch_accessibility_enabler.cc", "accessibility/touch_accessibility_enabler.cc",
"accessibility/touch_accessibility_enabler.h", "accessibility/touch_accessibility_enabler.h",
"accessibility/touch_exploration_controller.cc", "accessibility/touch_exploration_controller.cc",
...@@ -1541,6 +1545,7 @@ test("ash_unittests") { ...@@ -1541,6 +1545,7 @@ test("ash_unittests") {
"accessibility/accessibility_focus_ring_controller_unittest.cc", "accessibility/accessibility_focus_ring_controller_unittest.cc",
"accessibility/accessibility_highlight_controller_unittest.cc", "accessibility/accessibility_highlight_controller_unittest.cc",
"accessibility/accessibility_panel_layout_manager_unittest.cc", "accessibility/accessibility_panel_layout_manager_unittest.cc",
"accessibility/key_accessibility_enabler_unittest.cc",
"accessibility/touch_accessibility_enabler_unittest.cc", "accessibility/touch_accessibility_enabler_unittest.cc",
"accessibility/touch_exploration_controller_unittest.cc", "accessibility/touch_exploration_controller_unittest.cc",
"accessibility/touch_exploration_manager_unittest.cc", "accessibility/touch_exploration_manager_unittest.cc",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "ash/strings/grit/ash_strings.h" #include "ash/strings/grit/ash_strings.h"
#include "ash/system/power/backlights_forced_off_setter.h" #include "ash/system/power/backlights_forced_off_setter.h"
#include "ash/system/power/scoped_backlights_forced_off.h" #include "ash/system/power/scoped_backlights_forced_off.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "chromeos/audio/cras_audio_handler.h" #include "chromeos/audio/cras_audio_handler.h"
#include "components/pref_registry/pref_registry_syncable.h" #include "components/pref_registry/pref_registry_syncable.h"
...@@ -173,19 +174,21 @@ void ShowAccessibilityNotification(A11yNotificationType type) { ...@@ -173,19 +174,21 @@ void ShowAccessibilityNotification(A11yNotificationType type) {
base::string16 text; base::string16 text;
base::string16 title; base::string16 title;
if (type == A11yNotificationType::kSpokenFeedbackBrailleEnabled) { if (type == A11yNotificationType::kBrailleDisplayConnected) {
text =
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED);
title = l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_BRAILLE_ENABLED_TITLE);
} else if (type == A11yNotificationType::kBrailleDisplayConnected) {
text = l10n_util::GetStringUTF16( text = l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED); IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED);
} else { } else {
bool is_tablet = Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled();
title = l10n_util::GetStringUTF16( title = l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_TITLE); type == A11yNotificationType::kSpokenFeedbackBrailleEnabled
text = ? IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_BRAILLE_ENABLED_TITLE
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED); : IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_TITLE);
text = l10n_util::GetStringUTF16(
is_tablet ? IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_TABLET
: IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED);
} }
message_center::RichNotificationData options; message_center::RichNotificationData options;
options.should_make_spoken_feedback_for_popup_updates = false; options.should_make_spoken_feedback_for_popup_updates = false;
......
// Copyright 2018 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/accessibility/key_accessibility_enabler.h"
#include "ash/accessibility/spoken_feedback_enabler.h"
#include "ash/shell.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ui/events/event.h"
namespace ash {
KeyAccessibilityEnabler::KeyAccessibilityEnabler() {
Shell::Get()->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
}
KeyAccessibilityEnabler::~KeyAccessibilityEnabler() {
Shell::Get()->RemovePreTargetHandler(this);
}
void KeyAccessibilityEnabler::OnKeyEvent(ui::KeyEvent* event) {
if ((event->type() != ui::ET_KEY_PRESSED &&
event->type() != ui::ET_KEY_RELEASED) ||
!Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled())
return;
if (event->key_code() == ui::VKEY_VOLUME_DOWN)
vol_down_pressed_ = event->type() == ui::ET_KEY_PRESSED;
else if (event->key_code() == ui::VKEY_VOLUME_UP)
vol_up_pressed_ = event->type() == ui::ET_KEY_PRESSED;
if (vol_down_pressed_ && vol_up_pressed_) {
event->StopPropagation();
if (!spoken_feedback_enabler_.get())
spoken_feedback_enabler_ = std::make_unique<SpokenFeedbackEnabler>();
} else if (spoken_feedback_enabler_.get()) {
spoken_feedback_enabler_.reset();
}
}
} // namespace ash
// Copyright 2018 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_ACCESSIBILITY_KEY_ACCESSIBILITY_ENABLER_H_
#define ASH_ACCESSIBILITY_KEY_ACCESSIBILITY_ENABLER_H_
#include "ash/ash_export.h"
#include "base/macros.h"
#include "ui/events/event_handler.h"
namespace ui {
class KeyEvent;
} // namespace ui
namespace ash {
class SpokenFeedbackEnabler;
// Toggles spoken feedback when the volume up and volume down keys are held for
// at least 5 seconds.
class ASH_EXPORT KeyAccessibilityEnabler : public ui::EventHandler {
public:
KeyAccessibilityEnabler();
~KeyAccessibilityEnabler() override;
private:
friend class KeyAccessibilityEnablerTest;
// Overridden from ui::EventHandler
void OnKeyEvent(ui::KeyEvent* event) override;
std::unique_ptr<SpokenFeedbackEnabler> spoken_feedback_enabler_;
bool vol_down_pressed_ = false;
bool vol_up_pressed_ = false;
DISALLOW_COPY_AND_ASSIGN(KeyAccessibilityEnabler);
};
} // namespace ash
#endif // ASH_ACCESSIBILITY_KEY_ACCESSIBILITY_ENABLER_H_
// Copyright 2018 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/accessibility/key_accessibility_enabler.h"
#include "ash/accessibility/accessibility_controller.h"
#include "ash/accessibility/accessibility_observer.h"
#include "ash/shell.h"
#include "ash/system/web_notification/web_notification_tray.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/run_loop.h"
#include "base/test/simple_test_tick_clock.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
namespace ash {
class KeyAccessibilityEnablerTest : public AshTestBase,
public AccessibilityObserver {
public:
KeyAccessibilityEnablerTest() {}
void SetUp() override {
WebNotificationTray::DisableAnimationsForTest(true);
ui::SetEventTickClockForTesting(&clock_);
AshTestBase::SetUp();
Shell::Get()->accessibility_controller()->AddObserver(this);
key_accessibility_enabler_ = Shell::Get()->key_accessibility_enabler();
}
void TearDown() override {
ui::SetEventTickClockForTesting(nullptr);
AshTestBase::TearDown();
}
void SendKeyEvent(ui::KeyEvent* event) {
// Tablet mode gets exited elsewhere, so we must force it enabled before
// each key event.
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
key_accessibility_enabler_->OnKeyEvent(event);
}
void WaitForAccessibilityStatusChanged() {
run_loop_ = std::make_unique<base::RunLoop>();
clock_.Advance(base::TimeDelta::FromMilliseconds(5000));
run_loop_->Run();
}
private:
// AccessibilityObserver:
void OnAccessibilityStatusChanged() override { run_loop_->Quit(); }
std::unique_ptr<base::RunLoop> run_loop_;
KeyAccessibilityEnabler* key_accessibility_enabler_;
base::SimpleTestTickClock clock_;
};
TEST_F(KeyAccessibilityEnablerTest, TwoVolumeKeyDown) {
ui::KeyEvent vol_down_press(ui::ET_KEY_PRESSED, ui::VKEY_VOLUME_DOWN,
ui::EF_NONE);
ui::KeyEvent vol_up_press(ui::ET_KEY_PRESSED, ui::VKEY_VOLUME_UP,
ui::EF_NONE);
ui::KeyEvent vol_down_release(ui::ET_KEY_RELEASED, ui::VKEY_VOLUME_DOWN,
ui::EF_NONE);
ui::KeyEvent vol_up_release(ui::ET_KEY_RELEASED, ui::VKEY_VOLUME_UP,
ui::EF_NONE);
AccessibilityController* controller =
Shell::Get()->accessibility_controller();
ASSERT_FALSE(controller->IsSpokenFeedbackEnabled());
SendKeyEvent(&vol_down_press);
SendKeyEvent(&vol_up_press);
WaitForAccessibilityStatusChanged();
ASSERT_TRUE(controller->IsSpokenFeedbackEnabled());
SendKeyEvent(&vol_down_release);
SendKeyEvent(&vol_up_release);
SendKeyEvent(&vol_down_press);
SendKeyEvent(&vol_up_press);
WaitForAccessibilityStatusChanged();
ASSERT_FALSE(controller->IsSpokenFeedbackEnabled());
}
} // namespace ash
// Copyright 2018 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/accessibility/spoken_feedback_enabler.h"
#include "ash/accessibility/accessibility_controller.h"
#include "ash/shell.h"
#include "ui/events/base_event_utils.h"
namespace ash {
namespace {
// Delay between timer callbacks. Each one plays a tick sound.
constexpr base::TimeDelta kTimerDelay = base::TimeDelta::FromMilliseconds(500);
// The number of ticks of the timer before the first sound is generated.
constexpr int kTimerTicksOfFirstSoundFeedback = 6;
// The number of ticks of the timer before toggling spoken feedback.
constexpr int kTimerTicksToToggleSpokenFeedback = 10;
} // namespace
SpokenFeedbackEnabler::SpokenFeedbackEnabler() {
start_time_ = ui::EventTimeForNow();
timer_.Start(FROM_HERE, kTimerDelay, this, &SpokenFeedbackEnabler::OnTimer);
}
SpokenFeedbackEnabler::~SpokenFeedbackEnabler() {}
void SpokenFeedbackEnabler::OnTimer() {
base::TimeTicks now = ui::EventTimeForNow();
double tick_count_f = (now - start_time_) / kTimerDelay;
int tick_count = roundf(tick_count_f);
AccessibilityController* delegate = Shell::Get()->accessibility_controller();
CHECK(delegate);
if (tick_count >= kTimerTicksOfFirstSoundFeedback &&
tick_count < kTimerTicksToToggleSpokenFeedback) {
delegate->PlaySpokenFeedbackToggleCountdown(tick_count);
} else if (tick_count == kTimerTicksToToggleSpokenFeedback) {
delegate->SetSpokenFeedbackEnabled(!delegate->IsSpokenFeedbackEnabled(),
A11Y_NOTIFICATION_SHOW);
timer_.Stop();
}
}
} // namespace ash
// Copyright 2018 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_ACCESSIBILITY_SPOKEN_FEEDBACK_ENABLER_H_
#define ASH_ACCESSIBILITY_SPOKEN_FEEDBACK_ENABLER_H_
#include "ash/ash_export.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
namespace ash {
// A class that enables ChromeVox based on a timer, providing progress
// sound feedback.
class ASH_EXPORT SpokenFeedbackEnabler {
public:
SpokenFeedbackEnabler();
~SpokenFeedbackEnabler();
private:
// Handles ticks of the timer.
void OnTimer();
// The start time.
base::TimeTicks start_time_;
// A timer that triggers repeatedly until either cancel or the desired time
// elapsed.
base::RepeatingTimer timer_;
DISALLOW_COPY_AND_ASSIGN(SpokenFeedbackEnabler);
};
} // namespace ash
#endif // ASH_ACCESSIBILITY_SPOKEN_FEEDBACK_ENABLER_H_
...@@ -208,6 +208,9 @@ This file contains the strings for ash. ...@@ -208,6 +208,9 @@ This file contains the strings for ash.
<message name="IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED" desc="The message shown on a notification when spoken feedback is enabled"> <message name="IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED" desc="The message shown on a notification when spoken feedback is enabled">
Press Ctrl + Alt + Z to disable spoken feedback. Press Ctrl + Alt + Z to disable spoken feedback.
</message> </message>
<message name="IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_TABLET" desc="The message shown on a notification when spoken feedback is enabled on a tablet">
Press and hold both volume keys for five seconds to disable spoken feedback.
</message>
<message name="IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_TITLE" desc="The title message shown on a notification when spoken feedback is enabled"> <message name="IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_TITLE" desc="The title message shown on a notification when spoken feedback is enabled">
ChromeVox enabled ChromeVox enabled
</message> </message>
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "ash/accessibility/accessibility_controller.h" #include "ash/accessibility/accessibility_controller.h"
#include "ash/accessibility/accessibility_delegate.h" #include "ash/accessibility/accessibility_delegate.h"
#include "ash/accessibility/accessibility_focus_ring_controller.h" #include "ash/accessibility/accessibility_focus_ring_controller.h"
#include "ash/accessibility/key_accessibility_enabler.h"
#include "ash/app_list/app_list_controller_impl.h" #include "ash/app_list/app_list_controller_impl.h"
#include "ash/ash_constants.h" #include "ash/ash_constants.h"
#include "ash/assistant/ash_assistant_controller.h" #include "ash/assistant/ash_assistant_controller.h"
...@@ -862,6 +863,7 @@ Shell::~Shell() { ...@@ -862,6 +863,7 @@ Shell::~Shell() {
partial_magnification_controller_.reset(); partial_magnification_controller_.reset();
highlighter_controller_.reset(); highlighter_controller_.reset();
voice_interaction_controller_.reset(); voice_interaction_controller_.reset();
key_accessibility_enabler_.reset();
// This also deletes all RootWindows. Note that we invoke Shutdown() on // This also deletes all RootWindows. Note that we invoke Shutdown() on
// WindowTreeHostManager before resetting |window_tree_host_manager_|, since // WindowTreeHostManager before resetting |window_tree_host_manager_|, since
...@@ -1263,6 +1265,8 @@ void Shell::Init(ui::ContextFactory* context_factory, ...@@ -1263,6 +1265,8 @@ void Shell::Init(ui::ContextFactory* context_factory,
split_view_controller_.reset(new SplitViewController()); split_view_controller_.reset(new SplitViewController());
key_accessibility_enabler_ = std::make_unique<KeyAccessibilityEnabler>();
// The compositor thread and main message loop have to be running in // The compositor thread and main message loop have to be running in
// order to create mirror window. Run it after the main message loop // order to create mirror window. Run it after the main message loop
// is started. // is started.
......
...@@ -116,6 +116,7 @@ class HighlighterController; ...@@ -116,6 +116,7 @@ class HighlighterController;
class ImeController; class ImeController;
class ImmersiveContextAsh; class ImmersiveContextAsh;
class ImmersiveHandlerFactoryAsh; class ImmersiveHandlerFactoryAsh;
class KeyAccessibilityEnabler;
class KeyboardBrightnessControlDelegate; class KeyboardBrightnessControlDelegate;
class KeyboardUI; class KeyboardUI;
class LaserPointerController; class LaserPointerController;
...@@ -410,6 +411,9 @@ class ASH_EXPORT Shell : public SessionObserver, ...@@ -410,6 +411,9 @@ class ASH_EXPORT Shell : public SessionObserver,
return high_contrast_controller_.get(); return high_contrast_controller_.get();
} }
ImeController* ime_controller() { return ime_controller_.get(); } ImeController* ime_controller() { return ime_controller_.get(); }
KeyAccessibilityEnabler* key_accessibility_enabler() {
return key_accessibility_enabler_.get();
}
KeyboardBrightnessControlDelegate* keyboard_brightness_control_delegate() { KeyboardBrightnessControlDelegate* keyboard_brightness_control_delegate() {
return keyboard_brightness_control_delegate_.get(); return keyboard_brightness_control_delegate_.get();
} }
...@@ -864,6 +868,10 @@ class ASH_EXPORT Shell : public SessionObserver, ...@@ -864,6 +868,10 @@ class ASH_EXPORT Shell : public SessionObserver,
// hide the cursor on Windows. // hide the cursor on Windows.
std::unique_ptr<::wm::CursorManager> cursor_manager_; std::unique_ptr<::wm::CursorManager> cursor_manager_;
// Enables spoken feedback accessibility based on a press and hold of both
// volume keys.
std::unique_ptr<KeyAccessibilityEnabler> key_accessibility_enabler_;
// For testing only: simulate that a modal window is open // For testing only: simulate that a modal window is open
bool simulate_modal_window_open_for_test_ = false; bool simulate_modal_window_open_for_test_ = false;
......
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