Commit 8df286c2 authored by David Tseng's avatar David Tseng Committed by Commit Bot

Moves load progress tones from js to native

R=dmazzoni@chromium.org

Bug: 1046430
Change-Id: I134e5b7bfa2f38ea7143baad2f0f43f2ecc0dc18
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2149400
Commit-Queue: David Tseng <dtseng@chromium.org>
Reviewed-by: default avatarNancy Wang <nancylingwang@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#759912}
parent 3fc8ab94
...@@ -198,6 +198,74 @@ class AccessibilityPanelWidgetObserver : public views::WidgetObserver { ...@@ -198,6 +198,74 @@ class AccessibilityPanelWidgetObserver : public views::WidgetObserver {
DISALLOW_COPY_AND_ASSIGN(AccessibilityPanelWidgetObserver); DISALLOW_COPY_AND_ASSIGN(AccessibilityPanelWidgetObserver);
}; };
// Responsible for deferring ChromeVox load until a text-to-speech voice is
// ready to be used. Plays progress tones while waiting.
class ChromeVoxDeferredLoader : public content::UtteranceEventDelegate,
public content::VoicesChangedDelegate {
public:
explicit ChromeVoxDeferredLoader(AccessibilityManager* manager)
: manager_(manager) {
Profile* profile = manager_->profile();
if (profile->HasOffTheRecordProfile())
profile = profile->GetOffTheRecordProfile();
std::vector<content::VoiceData> voices;
content::TtsController::GetInstance()->GetVoices(profile, &voices);
if (voices.empty())
content::TtsController::GetInstance()->AddVoicesChangedDelegate(this);
else
SendWarmupUtterance();
}
~ChromeVoxDeferredLoader() override {
content::TtsController::GetInstance()->RemoveVoicesChangedDelegate(this);
content::TtsController::GetInstance()->RemoveUtteranceEventDelegate(this);
manager_->UnloadChromeVox();
}
private:
// content::UtteranceEventDelegate:
void OnTtsEvent(content::TtsUtterance* utterance,
content::TtsEventType event_type,
int char_index,
int length,
const std::string& error_message) override {
utterance->SetEventDelegate(nullptr);
timer_.Stop();
manager_->LoadChromeVox();
}
// content::VoicesChangedDelegate:
void OnVoicesChanged() override {
Profile* profile = manager_->profile();
if (profile->HasOffTheRecordProfile())
profile = profile->GetOffTheRecordProfile();
std::vector<content::VoiceData> voices;
content::TtsController::GetInstance()->GetVoices(profile, &voices);
if (!voices.empty()) {
content::TtsController::GetInstance()->RemoveVoicesChangedDelegate(this);
SendWarmupUtterance();
}
}
void SendWarmupUtterance() {
Profile* profile = manager_->profile();
if (profile->HasOffTheRecordProfile())
profile = profile->GetOffTheRecordProfile();
std::unique_ptr<content::TtsUtterance> utterance =
content::TtsUtterance::Create(profile);
utterance->SetEventDelegate(this);
content::TtsController::GetInstance()->SpeakOrEnqueue(std::move(utterance));
timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(500), this,
&ChromeVoxDeferredLoader::OnTimer);
}
void OnTimer() { manager_->PlaySpokenFeedbackToggleCountdown(tick_count_++); }
AccessibilityManager* manager_;
int tick_count_ = 0;
base::RepeatingTimer timer_;
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// AccessibilityStatusEventDetails // AccessibilityStatusEventDetails
...@@ -482,11 +550,10 @@ void AccessibilityManager::OnSpokenFeedbackChanged() { ...@@ -482,11 +550,10 @@ void AccessibilityManager::OnSpokenFeedbackChanged() {
NotifyAccessibilityStatusChanged(details); NotifyAccessibilityStatusChanged(details);
if (enabled) { if (enabled) {
chromevox_loader_->Load( chromevox_deferred_loader_ =
profile_, base::BindRepeating(&AccessibilityManager::PostLoadChromeVox, std::make_unique<ChromeVoxDeferredLoader>(this);
weak_ptr_factory_.GetWeakPtr()));
} else { } else {
chromevox_loader_->Unload(); chromevox_deferred_loader_.reset();
} }
UpdateBrailleImeState(); UpdateBrailleImeState();
} }
...@@ -1326,6 +1393,21 @@ void AccessibilityManager::OnShutdown(extensions::ExtensionRegistry* registry) { ...@@ -1326,6 +1393,21 @@ void AccessibilityManager::OnShutdown(extensions::ExtensionRegistry* registry) {
extension_registry_observer_.Remove(registry); extension_registry_observer_.Remove(registry);
} }
void AccessibilityManager::LoadChromeVox() {
chromevox_loader_->Load(
profile_, base::BindRepeating(&AccessibilityManager::PostLoadChromeVox,
weak_ptr_factory_.GetWeakPtr()));
}
void AccessibilityManager::UnloadChromeVox() {
// In browser_tests unloading the ChromeVox extension can race with shutdown.
// http://crbug.com/801700
if (app_terminating_)
return;
chromevox_loader_->Unload();
}
void AccessibilityManager::PostLoadChromeVox() { void AccessibilityManager::PostLoadChromeVox() {
// In browser_tests loading the ChromeVox extension can race with shutdown. // In browser_tests loading the ChromeVox extension can race with shutdown.
// http://crbug.com/801700 // http://crbug.com/801700
......
...@@ -91,6 +91,7 @@ typedef AccessibilityStatusCallbackList::Subscription ...@@ -91,6 +91,7 @@ typedef AccessibilityStatusCallbackList::Subscription
AccessibilityStatusSubscription; AccessibilityStatusSubscription;
class AccessibilityPanelWidgetObserver; class AccessibilityPanelWidgetObserver;
class ChromeVoxDeferredLoader;
enum class PlaySoundOption { enum class PlaySoundOption {
// The sound is always played. // The sound is always played.
...@@ -362,6 +363,8 @@ class AccessibilityManager ...@@ -362,6 +363,8 @@ class AccessibilityManager
~AccessibilityManager() override; ~AccessibilityManager() override;
private: private:
void LoadChromeVox();
void UnloadChromeVox();
void PostLoadChromeVox(); void PostLoadChromeVox();
void PostUnloadChromeVox(); void PostUnloadChromeVox();
void PostSwitchChromeVoxProfile(); void PostSwitchChromeVoxProfile();
...@@ -501,10 +504,14 @@ class AccessibilityManager ...@@ -501,10 +504,14 @@ class AccessibilityManager
// Used to set the audio focus enforcement type for ChromeVox. // Used to set the audio focus enforcement type for ChromeVox.
mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_manager_; mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_manager_;
// Handles deferred ChromeVox load.
std::unique_ptr<ChromeVoxDeferredLoader> chromevox_deferred_loader_;
base::WeakPtrFactory<AccessibilityManager> weak_ptr_factory_{this}; base::WeakPtrFactory<AccessibilityManager> weak_ptr_factory_{this};
friend class DictationTest; friend class DictationTest;
friend class SwitchAccessTest; friend class SwitchAccessTest;
friend class ChromeVoxDeferredLoader;
DISALLOW_COPY_AND_ASSIGN(AccessibilityManager); DISALLOW_COPY_AND_ASSIGN(AccessibilityManager);
}; };
......
...@@ -152,7 +152,15 @@ void LoggedInSpokenFeedbackTest::EnableChromeVox() { ...@@ -152,7 +152,15 @@ void LoggedInSpokenFeedbackTest::EnableChromeVox() {
ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
AccessibilityManager::Get()->EnableSpokenFeedback(true); AccessibilityManager::Get()->EnableSpokenFeedback(true);
// AccessibilityManager sends a warmup utterance prior to actually loading
// ChromeVox.
sm_.ExpectSpeech("");
// The next utterance comes from ChromeVox signaling it is ready.
sm_.ExpectSpeechPattern("*"); sm_.ExpectSpeechPattern("*");
// Injects js to disable earcons.
sm_.Call([this]() { DisableEarcons(); }); sm_.Call([this]() { DisableEarcons(); });
} }
......
...@@ -16,17 +16,8 @@ GEN_INCLUDE(['../../testing/mock_feedback.js']); ...@@ -16,17 +16,8 @@ GEN_INCLUDE(['../../testing/mock_feedback.js']);
ChromeVoxAnnotationTest = class extends ChromeVoxNextE2ETest { ChromeVoxAnnotationTest = class extends ChromeVoxNextE2ETest {
/** @override */ /** @override */
testGenCppIncludes() { testGenCppIncludes() {
super.testGenCppIncludes();
GEN(` GEN(`
// The following includes are copy-pasted from chromevox_e2e_test_base.js.
#include "ash/accessibility/accessibility_delegate.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "base/callback.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/common/extensions/extension_constants.h"
#include "extensions/common/extension_l10n_util.h"
// The following includes are necessary for this test file.
#include "base/command_line.h" #include "base/command_line.h"
#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/accessibility_switches.h"
#include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_switches.h"
...@@ -38,14 +29,8 @@ ChromeVoxAnnotationTest = class extends ChromeVoxNextE2ETest { ...@@ -38,14 +29,8 @@ ChromeVoxAnnotationTest = class extends ChromeVoxNextE2ETest {
GEN(` GEN(`
base::CommandLine::ForCurrentProcess()->AppendSwitch( base::CommandLine::ForCurrentProcess()->AppendSwitch(
::switches::kEnableExperimentalAccessibilityChromeVoxAnnotations); ::switches::kEnableExperimentalAccessibilityChromeVoxAnnotations);
// Copy-pasted from chromevox_e2e_test_base.js.
auto allow = extension_l10n_util::AllowGzippedMessagesAllowedForTest();
base::Closure load_cb =
base::Bind(&chromeos::AccessibilityManager::EnableSpokenFeedback,
base::Unretained(chromeos::AccessibilityManager::Get()),
true);
WaitForExtension(extension_misc::kChromeVoxExtensionId, load_cb);
`); `);
super.testGenPreamble();
} }
assertNumberOfAnnotationsForUrl(url, numAnnotations) { assertNumberOfAnnotationsForUrl(url, numAnnotations) {
......
...@@ -173,29 +173,6 @@ Background = class extends ChromeVoxState { ...@@ -173,29 +173,6 @@ Background = class extends ChromeVoxState {
// Set the darkScreen state to false, since the display will be on whenever // Set the darkScreen state to false, since the display will be on whenever
// ChromeVox starts. // ChromeVox starts.
sessionStorage.setItem('darkScreen', 'false'); sessionStorage.setItem('darkScreen', 'false');
// A self-contained class to start and stop progress sounds before any
// speech has been generated on startup. This is important in cases where
// speech is severely delayed.
/** @implements {TtsCapturingEventListener} */
const ProgressPlayer = class {
constructor() {
ChromeVox.tts.addCapturingEventListener(this);
ChromeVox.earcons.playEarcon(Earcon.CHROMEVOX_LOADING);
}
/** @override */
onTtsStart() {
ChromeVox.earcons.playEarcon(Earcon.CHROMEVOX_LOADED);
ChromeVox.tts.removeCapturingEventListener(this);
}
/** @override */
onTtsEnd() {}
/** @override */
onTtsInterrupted() {}
};
new ProgressPlayer();
} }
/** /**
......
...@@ -12,17 +12,8 @@ GEN_INCLUDE(['../testing/mock_feedback.js']); ...@@ -12,17 +12,8 @@ GEN_INCLUDE(['../testing/mock_feedback.js']);
ChromeVoxLocaleOutputHelperTest = class extends ChromeVoxNextE2ETest { ChromeVoxLocaleOutputHelperTest = class extends ChromeVoxNextE2ETest {
/** @override */ /** @override */
testGenCppIncludes() { testGenCppIncludes() {
super.testGenCppIncludes();
GEN(` GEN(`
// The following includes are copy-pasted from chromevox_e2e_test_base.js.
#include "ash/accessibility/accessibility_delegate.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "base/callback.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/common/extensions/extension_constants.h"
#include "extensions/common/extension_l10n_util.h"
// The following includes are necessary for this test file.
#include "base/command_line.h" #include "base/command_line.h"
#include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/accessibility_switches.h"
#include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_switches.h"
...@@ -37,15 +28,8 @@ ChromeVoxLocaleOutputHelperTest = class extends ChromeVoxNextE2ETest { ...@@ -37,15 +28,8 @@ ChromeVoxLocaleOutputHelperTest = class extends ChromeVoxNextE2ETest {
base::CommandLine::ForCurrentProcess()->AppendSwitch( base::CommandLine::ForCurrentProcess()->AppendSwitch(
::switches::kEnableExperimentalAccessibilityChromeVoxLanguageSwitching); ::switches::kEnableExperimentalAccessibilityChromeVoxLanguageSwitching);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(::switches::kLang, "en-US"); base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(::switches::kLang, "en-US");
// Copy-pasted from chromevox_e2e_test_base.js.
auto allow = extension_l10n_util::AllowGzippedMessagesAllowedForTest();
base::Closure load_cb =
base::Bind(&chromeos::AccessibilityManager::EnableSpokenFeedback,
base::Unretained(chromeos::AccessibilityManager::Get()),
true);
WaitForExtension(extension_misc::kChromeVoxExtensionId, load_cb);
`); `);
super.testGenPreamble();
} }
/** @override */ /** @override */
...@@ -617,4 +601,4 @@ TEST_F( ...@@ -617,4 +601,4 @@ TEST_F(
.expectSpeechWithLocale('pt', 'português: Portuguese'); .expectSpeechWithLocale('pt', 'português: Portuguese');
mockFeedback.replay(); mockFeedback.replay();
}); });
}); });
\ No newline at end of file
...@@ -23,6 +23,7 @@ ChromeVoxE2ETest = class extends testing.Test { ...@@ -23,6 +23,7 @@ ChromeVoxE2ETest = class extends testing.Test {
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/browser/chromeos/accessibility/speech_monitor.h"
#include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_constants.h"
#include "extensions/common/extension_l10n_util.h" #include "extensions/common/extension_l10n_util.h"
`); `);
...@@ -31,6 +32,11 @@ ChromeVoxE2ETest = class extends testing.Test { ...@@ -31,6 +32,11 @@ ChromeVoxE2ETest = class extends testing.Test {
/** @override */ /** @override */
testGenPreamble() { testGenPreamble() {
GEN(` GEN(`
// SpeechMonitor swaps in a custom TtsPlatform to mock out events and
// voices. Do this for the current call stack to catch deferred load.
chromeos::SpeechMonitor speech_monitor;
auto allow = extension_l10n_util::AllowGzippedMessagesAllowedForTest(); auto allow = extension_l10n_util::AllowGzippedMessagesAllowedForTest();
base::Closure load_cb = base::Closure load_cb =
base::Bind(&chromeos::AccessibilityManager::EnableSpokenFeedback, base::Bind(&chromeos::AccessibilityManager::EnableSpokenFeedback,
......
...@@ -2435,6 +2435,9 @@ IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest, EnableChromeVox) { ...@@ -2435,6 +2435,9 @@ IN_PROC_BROWSER_TEST_F(HotseatShelfAppBrowserTest, EnableChromeVox) {
ui::test::EventGenerator event_generator(controller->GetRootWindow()); ui::test::EventGenerator event_generator(controller->GetRootWindow());
auto* generator_ptr = &event_generator; auto* generator_ptr = &event_generator;
// AccessibilityManager sends an empty warmup utterance first.
speech_monitor.ExpectSpeech("");
// Wait for ChromeVox to start reading anything. // Wait for ChromeVox to start reading anything.
speech_monitor.ExpectSpeechPattern("*"); speech_monitor.ExpectSpeechPattern("*");
speech_monitor.Call([this]() { speech_monitor.Call([this]() {
......
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