1c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Copyright 2014 The Chromium Authors. All rights reserved. 2c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Use of this source code is governed by a BSD-style license that can be 3c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// found in the LICENSE file. 4c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 5c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include <queue> 6c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 7c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ash/shell.h" 8c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ash/system/tray/system_tray.h" 9c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "base/command_line.h" 10c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "base/strings/string_util.h" 11c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/app/chrome_command_ids.h" 12c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/chromeos/accessibility/accessibility_manager.h" 13c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/chromeos/accessibility/speech_monitor.h" 14c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/chromeos/login/ui/login_display_host.h" 15c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" 16c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/chromeos/login/ui/webui_login_view.h" 17c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/chromeos/profiles/profile_helper.h" 18c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h" 19c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/speech/tts_controller.h" 20c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/speech/tts_platform.h" 21c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/ui/browser.h" 22c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/ui/browser_commands.h" 23c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/ui/browser_window.h" 24c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/ui/tabs/tab_strip_model.h" 25c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/common/chrome_switches.h" 26c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/common/extensions/extension_constants.h" 27c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/test/base/in_process_browser_test.h" 28c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/test/base/interactive_test_utils.h" 29c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/test/base/testing_profile.h" 30c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/test/base/ui_test_utils.h" 31c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chromeos/chromeos_switches.h" 32c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chromeos/login/user_names.h" 33c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "content/public/common/url_constants.h" 34c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "content/public/test/browser_test_utils.h" 35c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "content/public/test/test_utils.h" 36c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "extensions/browser/extension_host.h" 37c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "extensions/browser/process_manager.h" 38c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "testing/gtest/include/gtest/gtest.h" 39c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ui/base/test/ui_controls.h" 40c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ui/views/widget/widget.h" 41c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 42c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathusing extensions::api::braille_display_private::StubBrailleController; 43c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 44c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathnamespace chromeos { 45c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 46c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// 47c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Spoken feedback tests only in a logged in user's window. 48c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// 49c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 50c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathclass LoggedInSpokenFeedbackTest : public InProcessBrowserTest { 51c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath protected: 52c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath LoggedInSpokenFeedbackTest() {} 53c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath virtual ~LoggedInSpokenFeedbackTest() {} 54c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 55c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 56c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath AccessibilityManager::SetBrailleControllerForTest(&braille_controller_); 57c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 58c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 59c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath virtual void TearDownOnMainThread() OVERRIDE { 60c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath AccessibilityManager::SetBrailleControllerForTest(NULL); 61c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 62c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 63c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void SendKeyPress(ui::KeyboardCode key) { 64c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_NO_FATAL_FAILURE( 65c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE( 66c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui_test_utils::SendKeyPressToWindowSync( 67c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath NULL, key, false, false, false, false))); 68c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 69c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 70c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void SendKeyPressWithControl(ui::KeyboardCode key) { 71c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_NO_FATAL_FAILURE( 72c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE( 73c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui_test_utils::SendKeyPressToWindowSync( 74c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath NULL, key, true, false, false, false))); 75c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 76c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 77c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void SendKeyPressWithSearchAndShift(ui::KeyboardCode key) { 78c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_NO_FATAL_FAILURE( 79c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE( 80c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui_test_utils::SendKeyPressToWindowSync( 817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez NULL, key, false, true, false, true))); 827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez } 837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez void RunJavaScriptInChromeVoxBackgroundPage(const std::string& script) { 857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez extensions::ExtensionHost* host = 86c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath extensions::ExtensionSystem::Get(browser()->profile())-> 87c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath process_manager()->GetBackgroundHostForExtension( 88c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath extension_misc::kChromeVoxExtensionId); 89c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath CHECK(content::ExecuteScript(host->host_contents(), script)); 90c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 91c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 92c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void SimulateTouchScreenInChromeVox() { 93c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // ChromeVox looks at whether 'ontouchstart' exists to know whether 94c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // or not it should respond to hover events. Fake it so that touch 95c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // exploration events get spoken. 96c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath RunJavaScriptInChromeVoxBackgroundPage( 97c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath "window.ontouchstart = function() {};"); 98c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 99c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 100c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void DisableEarcons() { 101c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Playing earcons from within a test is not only annoying if you're 102c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // running the test locally, but seems to cause crashes 103c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // (http://crbug.com/396507). Work around this by just telling 104c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // ChromeVox to not ever play earcons (prerecorded sound effects). 105c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath RunJavaScriptInChromeVoxBackgroundPage( 106c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath "cvox.ChromeVox.earcons.playEarcon = function() {};"); 107c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 108c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 109c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void LoadChromeVoxAndThenNavigateToURL(const GURL& url) { 110c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // The goal of this helper function is to avoid race conditions between 111c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // the page loading and the ChromeVox extension loading and fully 112c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // initializing. To do this, we first load a test url that repeatedly 113c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // asks ChromeVox to speak 'ready', then we load ChromeVox and block 114c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // until we get that 'ready' speech. 115c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 116c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui_test_utils::NavigateToURL( 117c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath browser(), 118c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath GURL("data:text/html;charset=utf-8," 119c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath "<script>" 120c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath "window.setInterval(function() {" 121c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath " try {" 122c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath " cvox.Api.speak('ready');" 123c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath " } catch (e) {}" 124c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath "}, 100);" 1257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez "</script>")); 1267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez EXPECT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); 127c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath AccessibilityManager::Get()->EnableSpokenFeedback( 128c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath true, ash::A11Y_NOTIFICATION_NONE); 129c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 1307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez // Block until we get "ready". 1317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez while (speech_monitor_.GetNextUtterance() != "ready") { 132c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 1337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 134c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Now load the requested url. 135c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui_test_utils::NavigateToURL(browser(), url); 136c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 1377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 138c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void PressRepeatedlyUntilUtterance(ui::KeyboardCode key, 1397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez const std::string& expected_utterance) { 1407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez // This helper function is needed when you want to poll for something 1417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez // that happens asynchronously. Keep pressing |key|, until 142c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // the speech feedback that follows is |expected_utterance|. 143c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Note that this doesn't work if pressing that key doesn't speak anything 144c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // at all before the asynchronous event occurred. 145c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath while (true) { 146c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SendKeyPress(key); 147c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath const std::string& utterance = speech_monitor_.GetNextUtterance(); 148c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath if (utterance == expected_utterance) 149c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath break; 150c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 151c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 152c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 153c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SpeechMonitor speech_monitor_; 154c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 155c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath private: 156c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath StubBrailleController braille_controller_; 157c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath DISALLOW_COPY_AND_ASSIGN(LoggedInSpokenFeedbackTest); 158c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}; 159c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 160c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIN_PROC_BROWSER_TEST_F(LoggedInSpokenFeedbackTest, AddBookmark) { 161c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); 162c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 1637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez AccessibilityManager::Get()->EnableSpokenFeedback( 1647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez true, ash::A11Y_NOTIFICATION_NONE); 165c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage()); 166c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath DisableEarcons(); 167c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 1687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR); 1697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 170c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Create a bookmark with title "foo". 1717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez chrome::ExecuteCommand(browser(), IDC_BOOKMARK_PAGE); 172c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_EQ("Bookmark added!,", speech_monitor_.GetNextUtterance()); 173c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_EQ("about blank,", speech_monitor_.GetNextUtterance()); 174c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_EQ("Bookmark name,", speech_monitor_.GetNextUtterance()); 1757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez EXPECT_EQ("text box", speech_monitor_.GetNextUtterance()); 176c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 1777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez SendKeyPress(ui::VKEY_F); 1787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez EXPECT_EQ("f", speech_monitor_.GetNextUtterance()); 1797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez SendKeyPress(ui::VKEY_O); 180c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_EQ("o", speech_monitor_.GetNextUtterance()); 181c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SendKeyPress(ui::VKEY_O); 182c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_EQ("o", speech_monitor_.GetNextUtterance()); 183c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 184c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SendKeyPress(ui::VKEY_TAB); 185c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_EQ("Bookmarks bar,", speech_monitor_.GetNextUtterance()); 186c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_EQ("Bookmark folder,", speech_monitor_.GetNextUtterance()); 187c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_TRUE(MatchPattern(speech_monitor_.GetNextUtterance(), "combo box*")); 188c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 189c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SendKeyPress(ui::VKEY_RETURN); 190c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 191c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXPECT_TRUE(MatchPattern(speech_monitor_.GetNextUtterance(), "*oolbar*")); 192c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Wait for active window change to be announced to avoid interference from 193c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // that below. 194c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath while (speech_monitor_.GetNextUtterance() != "window about blank tab") { 195c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Do nothing. 196c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 197 198 // Focus bookmarks bar and listen for "foo". 199 chrome::ExecuteCommand(browser(), IDC_FOCUS_BOOKMARKS); 200 while (true) { 201 std::string utterance = speech_monitor_.GetNextUtterance(); 202 VLOG(0) << "Got utterance: " << utterance; 203 if (utterance == "Bookmarks,") 204 break; 205 } 206 EXPECT_EQ("foo,", speech_monitor_.GetNextUtterance()); 207 EXPECT_EQ("button", speech_monitor_.GetNextUtterance()); 208} 209 210// 211// Spoken feedback tests in both a logged in browser window and guest mode. 212// 213 214enum SpokenFeedbackTestVariant { 215 kTestAsNormalUser, 216 kTestAsGuestUser 217}; 218 219class SpokenFeedbackTest 220 : public LoggedInSpokenFeedbackTest, 221 public ::testing::WithParamInterface<SpokenFeedbackTestVariant> { 222 protected: 223 SpokenFeedbackTest() {} 224 virtual ~SpokenFeedbackTest() {} 225 226 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 227 if (GetParam() == kTestAsGuestUser) { 228 command_line->AppendSwitch(chromeos::switches::kGuestSession); 229 command_line->AppendSwitch(::switches::kIncognito); 230 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, 231 "user"); 232 command_line->AppendSwitchASCII(chromeos::switches::kLoginUser, 233 chromeos::login::kGuestUserName); 234 } 235 } 236}; 237 238INSTANTIATE_TEST_CASE_P( 239 TestAsNormalAndGuestUser, 240 SpokenFeedbackTest, 241 ::testing::Values(kTestAsNormalUser, 242 kTestAsGuestUser)); 243 244IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, EnableSpokenFeedback) { 245 ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); 246 247 AccessibilityManager::Get()->EnableSpokenFeedback( 248 true, ash::A11Y_NOTIFICATION_NONE); 249 EXPECT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage()); 250} 251 252IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, FocusToolbar) { 253 ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); 254 255 AccessibilityManager::Get()->EnableSpokenFeedback( 256 true, ash::A11Y_NOTIFICATION_NONE); 257 EXPECT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage()); 258 DisableEarcons(); 259 260 chrome::ExecuteCommand(browser(), IDC_FOCUS_TOOLBAR); 261 // Might be "Google Chrome Toolbar" or "Chromium Toolbar". 262 EXPECT_TRUE(MatchPattern(speech_monitor_.GetNextUtterance(), "*oolbar*")); 263 EXPECT_EQ("Reload,", speech_monitor_.GetNextUtterance()); 264 EXPECT_EQ("button", speech_monitor_.GetNextUtterance()); 265} 266 267IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, TypeInOmnibox) { 268 ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); 269 270 AccessibilityManager::Get()->EnableSpokenFeedback( 271 true, ash::A11Y_NOTIFICATION_NONE); 272 EXPECT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage()); 273 DisableEarcons(); 274 275 // Wait for ChromeVox to finish speaking. 276 chrome::ExecuteCommand(browser(), IDC_FOCUS_LOCATION); 277 while (true) { 278 std::string utterance = speech_monitor_.GetNextUtterance(); 279 VLOG(0) << "Got utterance: " << utterance; 280 if (utterance == "text box") 281 break; 282 } 283 284 SendKeyPress(ui::VKEY_X); 285 EXPECT_EQ("x", speech_monitor_.GetNextUtterance()); 286 287 SendKeyPress(ui::VKEY_Y); 288 EXPECT_EQ("y", speech_monitor_.GetNextUtterance()); 289 290 SendKeyPress(ui::VKEY_Z); 291 EXPECT_EQ("z", speech_monitor_.GetNextUtterance()); 292 293 SendKeyPress(ui::VKEY_BACK); 294 EXPECT_EQ("z", speech_monitor_.GetNextUtterance()); 295} 296 297IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxShiftSearch) { 298 LoadChromeVoxAndThenNavigateToURL( 299 GURL("data:text/html;charset=utf-8,<button autofocus>Click me</button>")); 300 while (true) { 301 std::string utterance = speech_monitor_.GetNextUtterance(); 302 if (utterance == "Click me") 303 break; 304 } 305 EXPECT_EQ("Button", speech_monitor_.GetNextUtterance()); 306 307 // Press Search+Shift+/ to enter ChromeVox's "find in page". 308 SendKeyPressWithSearchAndShift(ui::VKEY_OEM_2); 309 EXPECT_EQ("Find in page.", speech_monitor_.GetNextUtterance()); 310 EXPECT_EQ("Enter a search query.", speech_monitor_.GetNextUtterance()); 311} 312 313IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxPrefixKey) { 314 LoadChromeVoxAndThenNavigateToURL( 315 GURL("data:text/html;charset=utf-8,<button autofocus>Click me</button>")); 316 while (true) { 317 std::string utterance = speech_monitor_.GetNextUtterance(); 318 if (utterance == "Click me") 319 break; 320 } 321 EXPECT_EQ("Button", speech_monitor_.GetNextUtterance()); 322 323 // Press the prefix key Ctrl+';' followed by '/' 324 // to enter ChromeVox's "find in page". 325 SendKeyPressWithControl(ui::VKEY_OEM_1); 326 SendKeyPress(ui::VKEY_OEM_2); 327 EXPECT_EQ("Find in page.", speech_monitor_.GetNextUtterance()); 328 EXPECT_EQ("Enter a search query.", speech_monitor_.GetNextUtterance()); 329} 330 331IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxNavigateAndSelect) { 332 LoadChromeVoxAndThenNavigateToURL( 333 GURL("data:text/html;charset=utf-8," 334 "<h1>Title</h1>" 335 "<button autofocus>Click me</button>")); 336 while (true) { 337 std::string utterance = speech_monitor_.GetNextUtterance(); 338 if (utterance == "Click me") 339 break; 340 } 341 EXPECT_EQ("Button", speech_monitor_.GetNextUtterance()); 342 343 // Press Search+Shift+Up to navigate to the previous item. 344 SendKeyPressWithSearchAndShift(ui::VKEY_UP); 345 EXPECT_EQ("Title", speech_monitor_.GetNextUtterance()); 346 EXPECT_EQ("Heading 1", speech_monitor_.GetNextUtterance()); 347 348 // Press Search+Shift+S to select the text. 349 SendKeyPressWithSearchAndShift(ui::VKEY_S); 350 EXPECT_EQ("Start selection", speech_monitor_.GetNextUtterance()); 351 EXPECT_EQ("Title", speech_monitor_.GetNextUtterance()); 352 EXPECT_EQ(", selected", speech_monitor_.GetNextUtterance()); 353 354 // Press again to end the selection. 355 SendKeyPressWithSearchAndShift(ui::VKEY_S); 356 EXPECT_EQ("End selection", speech_monitor_.GetNextUtterance()); 357 EXPECT_EQ("Title", speech_monitor_.GetNextUtterance()); 358} 359 360IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, ChromeVoxStickyMode) { 361 LoadChromeVoxAndThenNavigateToURL( 362 GURL("data:text/html;charset=utf-8," 363 "<label>Enter your name <input autofocus></label>" 364 "<p>One</p>" 365 "<h2>Two</h2>")); 366 while (speech_monitor_.GetNextUtterance() != "Enter your name") { 367 } 368 EXPECT_EQ("Edit text", speech_monitor_.GetNextUtterance()); 369 370 // Press the sticky-key sequence: Search Search. 371 SendKeyPress(ui::VKEY_LWIN); 372 SendKeyPress(ui::VKEY_LWIN); 373 EXPECT_EQ("Sticky mode enabled", speech_monitor_.GetNextUtterance()); 374 375 // Even once we hear "sticky mode enabled" from the ChromeVox background 376 // page, there's a short window of time when the content script still 377 // hasn't switched to sticky mode. That's why we're focused on a text box. 378 // Keep pressing the '/' key. If sticky mode is off, it will echo the word 379 // "slash". If sticky mode is on, it will open "Find in page". Keep pressing 380 // '/' until we get "Find in page.". 381 PressRepeatedlyUntilUtterance(ui::VKEY_OEM_2, "Find in page."); 382 EXPECT_EQ("Enter a search query.", speech_monitor_.GetNextUtterance()); 383 384 // Press Esc to exit Find in Page mode. 385 SendKeyPress(ui::VKEY_ESCAPE); 386 EXPECT_EQ("Exited", speech_monitor_.GetNextUtterance()); 387 EXPECT_EQ("Find in page.", speech_monitor_.GetNextUtterance()); 388 389 // Press N H to jump to the next heading. Skip over speech in-between 390 // but make sure we end up at the heading. 391 SendKeyPress(ui::VKEY_N); 392 SendKeyPress(ui::VKEY_H); 393 while (speech_monitor_.GetNextUtterance() != "Two") { 394 } 395 EXPECT_EQ("Heading 2", speech_monitor_.GetNextUtterance()); 396 397 // Press the up arrow to go to the previous element. 398 SendKeyPress(ui::VKEY_UP); 399 EXPECT_EQ("One", speech_monitor_.GetNextUtterance()); 400} 401 402IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, TouchExploreStatusTray) { 403 ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); 404 405 AccessibilityManager::Get()->EnableSpokenFeedback( 406 true, ash::A11Y_NOTIFICATION_NONE); 407 EXPECT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage()); 408 DisableEarcons(); 409 410 SimulateTouchScreenInChromeVox(); 411 412 // Send an accessibility hover event on the system tray, which is 413 // what we get when you tap it on a touch screen when ChromeVox is on. 414 ash::SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray(); 415 tray->NotifyAccessibilityEvent(ui::AX_EVENT_HOVER, true); 416 417 EXPECT_EQ("Status tray,", speech_monitor_.GetNextUtterance()); 418 EXPECT_TRUE(MatchPattern(speech_monitor_.GetNextUtterance(), "time*,")); 419 EXPECT_TRUE(MatchPattern(speech_monitor_.GetNextUtterance(), "Battery*,")); 420 EXPECT_EQ("button", speech_monitor_.GetNextUtterance()); 421} 422 423// 424// Spoken feedback tests that run only in guest mode. 425// 426 427class GuestSpokenFeedbackTest : public LoggedInSpokenFeedbackTest { 428 protected: 429 GuestSpokenFeedbackTest() {} 430 virtual ~GuestSpokenFeedbackTest() {} 431 432 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 433 command_line->AppendSwitch(chromeos::switches::kGuestSession); 434 command_line->AppendSwitch(::switches::kIncognito); 435 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); 436 command_line->AppendSwitchASCII(chromeos::switches::kLoginUser, 437 chromeos::login::kGuestUserName); 438 } 439 440 private: 441 DISALLOW_COPY_AND_ASSIGN(GuestSpokenFeedbackTest); 442}; 443 444IN_PROC_BROWSER_TEST_F(GuestSpokenFeedbackTest, FocusToolbar) { 445 ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); 446 447 AccessibilityManager::Get()->EnableSpokenFeedback( 448 true, ash::A11Y_NOTIFICATION_NONE); 449 EXPECT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage()); 450 DisableEarcons(); 451 452 chrome::ExecuteCommand(browser(), IDC_FOCUS_TOOLBAR); 453 // Might be "Google Chrome Toolbar" or "Chromium Toolbar". 454 EXPECT_TRUE(MatchPattern(speech_monitor_.GetNextUtterance(), "*oolbar*")); 455 EXPECT_EQ("Reload,", speech_monitor_.GetNextUtterance()); 456 EXPECT_EQ("button", speech_monitor_.GetNextUtterance()); 457} 458 459// 460// Spoken feedback tests of the out-of-box experience. 461// 462 463class OobeSpokenFeedbackTest : public InProcessBrowserTest { 464 protected: 465 OobeSpokenFeedbackTest() {} 466 virtual ~OobeSpokenFeedbackTest() {} 467 468 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 469 command_line->AppendSwitch(chromeos::switches::kLoginManager); 470 command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests); 471 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); 472 } 473 474 virtual void SetUpOnMainThread() OVERRIDE { 475 AccessibilityManager::Get()-> 476 SetProfileForTest(ProfileHelper::GetSigninProfile()); 477 } 478 479 SpeechMonitor speech_monitor_; 480 481 private: 482 DISALLOW_COPY_AND_ASSIGN(OobeSpokenFeedbackTest); 483}; 484 485// Test is flaky: http://crbug.com/346797 486IN_PROC_BROWSER_TEST_F(OobeSpokenFeedbackTest, DISABLED_SpokenFeedbackInOobe) { 487 ui_controls::EnableUIControls(); 488 ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); 489 490 LoginDisplayHost* login_display_host = LoginDisplayHostImpl::default_host(); 491 WebUILoginView* web_ui_login_view = login_display_host->GetWebUILoginView(); 492 views::Widget* widget = web_ui_login_view->GetWidget(); 493 gfx::NativeWindow window = widget->GetNativeWindow(); 494 495 AccessibilityManager::Get()->EnableSpokenFeedback( 496 true, ash::A11Y_NOTIFICATION_NONE); 497 EXPECT_TRUE(speech_monitor_.SkipChromeVoxEnabledMessage()); 498 499 EXPECT_EQ("Select your language:", speech_monitor_.GetNextUtterance()); 500 EXPECT_EQ("English ( United States)", speech_monitor_.GetNextUtterance()); 501 EXPECT_TRUE(MatchPattern(speech_monitor_.GetNextUtterance(), 502 "Combo box * of *")); 503 ASSERT_TRUE( 504 ui_test_utils::SendKeyPressToWindowSync( 505 window, ui::VKEY_TAB, false, false, false, false)); 506 EXPECT_EQ("Select your keyboard:", speech_monitor_.GetNextUtterance()); 507} 508 509} // namespace chromeos 510