blob: 8c3a7afc9ae94cc409a1342eba6015eabfc2dce2 [file] [log] [blame]
[email protected]1dfebfc2013-06-04 03:14:321// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
6
avi8a07d53892015-12-24 22:13:537#include <stddef.h>
8#include <stdint.h>
dcheng24002d02016-04-08 02:42:409
10#include <memory>
dcheng7c802f02015-12-31 16:09:5511#include <utility>
David Tseng8a5de492018-01-17 20:41:3712#include <vector>
avi8a07d53892015-12-24 22:13:5313
James Cook08e91dc2018-03-08 18:53:1914#include "ash/accessibility/accessibility_controller.h"
James Cookc63b9fd2017-08-18 18:48:3215#include "ash/public/cpp/ash_pref_names.h"
Qiang Xu56a75812018-03-15 00:28:3416#include "ash/public/interfaces/accessibility_focus_ring_controller.mojom.h"
Qiang Xu4e5853d382018-01-09 07:21:0717#include "ash/public/interfaces/constants.mojom.h"
dmazzoniff86e3472016-06-03 19:52:3218#include "ash/root_window_controller.h"
pkotwicz04d5c892015-01-15 00:05:3619#include "ash/shell.h"
pkotwicz04d5c892015-01-15 00:05:3620#include "ash/sticky_keys/sticky_keys_controller.h"
[email protected]44beb032014-06-11 06:24:3721#include "base/callback.h"
22#include "base/callback_helpers.h"
plundbladcf1d08f2015-09-28 09:18:5823#include "base/command_line.h"
fdorayba121422016-12-23 19:51:4824#include "base/memory/ptr_util.h"
[email protected]1dfebfc2013-06-04 03:14:3225#include "base/memory/singleton.h"
asvitkineb56637512016-09-01 19:41:4026#include "base/metrics/histogram_macros.h"
[email protected]ab38d192013-12-13 11:38:5827#include "base/path_service.h"
mgiuca30f75882017-03-28 02:07:1928#include "base/strings/string_piece.h"
[email protected]2e5e0b12014-05-07 13:30:2029#include "base/strings/string_split.h"
30#include "base/strings/string_util.h"
[email protected]0aae2fe2013-07-05 07:04:4231#include "base/values.h"
[email protected]1dfebfc2013-06-04 03:14:3232#include "chrome/browser/accessibility/accessibility_extension_api.h"
33#include "chrome/browser/browser_process.h"
[email protected]fdf40f3e2013-07-11 23:55:4634#include "chrome/browser/chrome_notification_types.h"
dmazzoni337c5af2016-09-13 23:08:5735#include "chrome/browser/chromeos/accessibility/accessibility_extension_loader.h"
David Tseng8a5de492018-01-17 20:41:3736#include "chrome/browser/chromeos/accessibility/dictation_chromeos.h"
pkotwicz04d5c892015-01-15 00:05:3637#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
Katie D4ea69442018-04-02 23:17:3038#include "chrome/browser/chromeos/accessibility/select_to_speak_event_handler.h"
elichtenbergc4b4bf462017-02-28 20:48:1039#include "chrome/browser/chromeos/accessibility/switch_access_event_handler.h"
dmazzoni16d2dec2016-12-19 23:27:5740#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
James Cook696fb106a2017-08-17 21:50:4441#include "chrome/browser/chromeos/ash_config.h"
dmazzoni16d2dec2016-12-19 23:27:5742#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
[email protected]e6f20642013-06-11 17:05:4643#include "chrome/browser/chromeos/profiles/profile_helper.h"
plundbladcf1d08f2015-09-28 09:18:5844#include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
[email protected]1dfebfc2013-06-04 03:14:3245#include "chrome/browser/extensions/extension_service.h"
[email protected]1dfebfc2013-06-04 03:14:3246#include "chrome/browser/profiles/profile.h"
47#include "chrome/browser/profiles/profile_manager.h"
Katie D6264a8e2018-02-07 02:32:2048#include "chrome/browser/speech/tts_controller.h"
Qiang Xudce8aeb2018-01-11 04:17:2849#include "chrome/browser/ui/singleton_tabs.h"
[email protected]ab38d192013-12-13 11:38:5850#include "chrome/common/chrome_paths.h"
[email protected]9848bf6c2014-05-09 12:34:0051#include "chrome/common/extensions/api/accessibility_private.h"
[email protected]dccba4f82014-05-29 00:52:5652#include "chrome/common/extensions/extension_constants.h"
[email protected]1dfebfc2013-06-04 03:14:3253#include "chrome/common/pref_names.h"
Qiang Xudce8aeb2018-01-11 04:17:2854#include "chrome/common/url_constants.h"
[email protected]b58d2f82014-08-09 05:36:1455#include "chrome/grit/browser_resources.h"
[email protected]ce89d9392013-12-11 21:05:2056#include "chromeos/audio/chromeos_sounds.h"
Dominic Mazzonic85a5c92017-08-31 18:53:3057#include "chromeos/chromeos_switches.h"
dtseng3a17f212017-03-25 08:58:5258#include "chromeos/dbus/dbus_thread_manager.h"
59#include "chromeos/dbus/power_manager_client.h"
brettwb1fc1b82016-02-02 00:19:0860#include "components/prefs/pref_member.h"
61#include "components/prefs/pref_service.h"
tbarziccd5ad222017-03-24 04:46:3162#include "components/session_manager/core/session_manager.h"
[email protected]1dfebfc2013-06-04 03:14:3263#include "content/public/browser/browser_accessibility_state.h"
[email protected]8c79e3f2013-10-30 01:05:1464#include "content/public/browser/browser_thread.h"
Qiang Xu95eea572018-02-17 08:10:3165#include "content/public/browser/focused_node_details.h"
[email protected]9cf54f362013-07-01 07:28:1266#include "content/public/browser/notification_details.h"
[email protected]1dfebfc2013-06-04 03:14:3267#include "content/public/browser/notification_service.h"
[email protected]9cf54f362013-07-01 07:28:1268#include "content/public/browser/notification_source.h"
[email protected]1dfebfc2013-06-04 03:14:3269#include "content/public/browser/web_ui.h"
plundbladcf1d08f2015-09-28 09:18:5870#include "content/public/common/content_switches.h"
bend32292b2016-10-07 00:21:5871#include "content/public/common/service_manager_connection.h"
reillyga3acbc12014-11-11 23:17:1272#include "extensions/browser/extension_registry.h"
[email protected]e4452d32013-11-15 23:07:4173#include "extensions/common/extension.h"
[email protected]fb820c02014-03-13 15:07:0874#include "extensions/common/extension_messages.h"
[email protected]1dfebfc2013-06-04 03:14:3275#include "extensions/common/extension_resource.h"
hanxi79f7a572015-03-09 20:46:5976#include "extensions/common/host_id.h"
Ken Rockot388ba4fc2018-02-10 17:23:4177#include "mash/public/mojom/launchable.mojom.h"
[email protected]12b0a842013-12-04 20:48:1378#include "media/audio/sounds/sounds_manager.h"
dtsengd50debe32016-12-29 06:23:3779#include "media/base/media_switches.h"
rockot734fb662016-10-15 16:41:3080#include "services/service_manager/public/cpp/connector.h"
Qiang Xuc4b05752018-02-13 20:10:2881#include "ui/accessibility/ax_enum_util.h"
jamescook2d60f032017-06-01 00:55:2182#include "ui/base/ime/chromeos/extension_ime_util.h"
[email protected]1dfebfc2013-06-04 03:14:3283#include "ui/base/resource/resource_bundle.h"
Scott Violet66193f72017-06-26 22:24:1884#include "ui/views/widget/widget.h"
jamescook9eb0f912017-02-03 19:13:3985#include "ui/views/widget/widget_observer.h"
Qiang Xudce8aeb2018-01-11 04:17:2886#include "url/gurl.h"
[email protected]1dfebfc2013-06-04 03:14:3287
[email protected]8c79e3f2013-10-30 01:05:1488using content::BrowserThread;
[email protected]8c79e3f2013-10-30 01:05:1489using extensions::api::braille_display_private::BrailleController;
90using extensions::api::braille_display_private::DisplayState;
[email protected]2e5e0b12014-05-07 13:30:2091using extensions::api::braille_display_private::KeyEvent;
plundbladcf1d08f2015-09-28 09:18:5892using extensions::api::braille_display_private::StubBrailleController;
[email protected]1dfebfc2013-06-04 03:14:3293
94namespace chromeos {
95
96namespace {
97
sadrulcdc2bb42016-07-13 19:44:5198// When this flag is set, system sounds will not be played.
Qiang Xu89af823e2017-12-05 04:04:4799constexpr char kAshDisableSystemSounds[] = "ash-disable-system-sounds";
sadrulcdc2bb42016-07-13 19:44:51100
Qiang Xu89af823e2017-12-05 04:04:47101static chromeos::AccessibilityManager* g_accessibility_manager = nullptr;
[email protected]1dfebfc2013-06-04 03:14:32102
Qiang Xu89af823e2017-12-05 04:04:47103static BrailleController* g_braille_controller_for_test = nullptr;
[email protected]8c79e3f2013-10-30 01:05:14104
105BrailleController* GetBrailleController() {
plundbladcf1d08f2015-09-28 09:18:58106 if (g_braille_controller_for_test)
107 return g_braille_controller_for_test;
108 // Don't use the real braille controller for tests to avoid automatically
109 // starting ChromeVox which confuses some tests.
110 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
Dominic Mazzonic85a5c92017-08-31 18:53:30111 if (command_line->HasSwitch(::switches::kTestType))
plundbladcf1d08f2015-09-28 09:18:58112 return StubBrailleController::GetInstance();
113 return BrailleController::GetInstance();
[email protected]8c79e3f2013-10-30 01:05:14114}
115
[email protected]1dfebfc2013-06-04 03:14:32116} // namespace
117
dmazzoni94a4f882015-11-13 05:46:52118class ChromeVoxPanelWidgetObserver : public views::WidgetObserver {
119 public:
120 ChromeVoxPanelWidgetObserver(views::Widget* widget,
121 AccessibilityManager* manager)
122 : widget_(widget), manager_(manager) {
123 widget_->AddObserver(this);
124 }
125
James Cook0c4f37ac02018-01-17 02:17:09126 ~ChromeVoxPanelWidgetObserver() override = default;
127
dmazzoni94a4f882015-11-13 05:46:52128 void OnWidgetClosing(views::Widget* widget) override {
129 CHECK_EQ(widget_, widget);
130 widget->RemoveObserver(this);
131 manager_->OnChromeVoxPanelClosing();
James Cook0c4f37ac02018-01-17 02:17:09132 // |this| is deleted.
dmazzoni94a4f882015-11-13 05:46:52133 }
134
135 void OnWidgetDestroying(views::Widget* widget) override {
136 CHECK_EQ(widget_, widget);
137 widget->RemoveObserver(this);
138 manager_->OnChromeVoxPanelDestroying();
James Cook0c4f37ac02018-01-17 02:17:09139 // |this| is deleted.
dmazzoni94a4f882015-11-13 05:46:52140 }
141
142 private:
143 views::Widget* widget_;
144 AccessibilityManager* manager_;
145
146 DISALLOW_COPY_AND_ASSIGN(ChromeVoxPanelWidgetObserver);
147};
148
[email protected]1dfebfc2013-06-04 03:14:32149///////////////////////////////////////////////////////////////////////////////
150// AccessibilityStatusEventDetails
151
152AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
[email protected]d8edc9c2014-02-25 00:06:03153 AccessibilityNotificationType notification_type,
Qiang Xu60e79032018-03-29 08:18:31154 bool enabled)
155 : notification_type(notification_type), enabled(enabled) {}
[email protected]1dfebfc2013-06-04 03:14:32156
157///////////////////////////////////////////////////////////////////////////////
[email protected]0aae2fe2013-07-05 07:04:42158//
[email protected]1dfebfc2013-06-04 03:14:32159// AccessibilityManager
160
161// static
162void AccessibilityManager::Initialize() {
163 CHECK(g_accessibility_manager == NULL);
164 g_accessibility_manager = new AccessibilityManager();
165}
166
167// static
168void AccessibilityManager::Shutdown() {
169 CHECK(g_accessibility_manager);
170 delete g_accessibility_manager;
171 g_accessibility_manager = NULL;
172}
173
174// static
175AccessibilityManager* AccessibilityManager::Get() {
176 return g_accessibility_manager;
177}
178
Qiang Xudce8aeb2018-01-11 04:17:28179// static
180void AccessibilityManager::ShowAccessibilityHelp(Browser* browser) {
181 ShowSingletonTab(browser, GURL(chrome::kChromeAccessibilityHelpURL));
182}
183
[email protected]d80f19302013-06-07 13:12:14184AccessibilityManager::AccessibilityManager()
185 : profile_(NULL),
Qiang(Joe) Xua0f644592017-12-01 02:16:50186 spoken_feedback_enabled_(false),
dmazzoni756089a22016-03-15 23:55:16187 select_to_speak_enabled_(false),
188 switch_access_enabled_(false),
[email protected]a81b2c32014-03-28 06:35:01189 braille_display_connected_(false),
[email protected]2e5e0b12014-05-07 13:30:20190 scoped_braille_observer_(this),
anand.ratn04aae9ef2014-09-16 04:16:51191 braille_ime_current_(false),
dmazzoni94a4f882015-11-13 05:46:52192 chromevox_panel_(nullptr),
dtsengfb6d7cd2016-01-20 23:00:13193 extension_registry_observer_(this),
anand.ratn04aae9ef2014-09-16 04:16:51194 weak_ptr_factory_(this) {
[email protected]1dfebfc2013-06-04 03:14:32195 notification_registrar_.Add(this,
[email protected]093d9ba2013-07-23 19:26:21196 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
[email protected]e6f20642013-06-11 17:05:46197 content::NotificationService::AllSources());
198 notification_registrar_.Add(this,
Yuki Awanod59b6492017-07-28 00:52:11199 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
200 content::NotificationService::AllSources());
James Cook12ccadd2017-10-09 03:53:34201 notification_registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED,
[email protected]1dfebfc2013-06-04 03:14:32202 content::NotificationService::AllSources());
James Cook12ccadd2017-10-09 03:53:34203 notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
[email protected]1dfebfc2013-06-04 03:14:32204 content::NotificationService::AllSources());
David Tseng768d7982017-12-21 00:20:11205 notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
206 content::NotificationService::AllSources());
Qiang Xu95eea572018-02-17 08:10:31207 notification_registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
208 content::NotificationService::AllSources());
[email protected]1488a035f2014-03-28 21:12:07209 input_method::InputMethodManager::Get()->AddObserver(this);
tbarziccd5ad222017-03-24 04:46:31210 session_manager::SessionManager::Get()->AddObserver(this);
[email protected]1488a035f2014-03-28 21:12:07211
[email protected]12b0a842013-12-04 20:48:13212 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
[email protected]ce89d9392013-12-11 21:05:20213 media::SoundsManager* manager = media::SoundsManager::Get();
214 manager->Initialize(SOUND_SHUTDOWN,
215 bundle.GetRawDataResource(IDR_SOUND_SHUTDOWN_WAV));
216 manager->Initialize(
217 SOUND_SPOKEN_FEEDBACK_ENABLED,
218 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_ENABLED_WAV));
219 manager->Initialize(
220 SOUND_SPOKEN_FEEDBACK_DISABLED,
221 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_DISABLED_WAV));
[email protected]07f3ea92014-08-14 05:23:38222 manager->Initialize(SOUND_PASSTHROUGH,
223 bundle.GetRawDataResource(IDR_SOUND_PASSTHROUGH_WAV));
224 manager->Initialize(SOUND_EXIT_SCREEN,
225 bundle.GetRawDataResource(IDR_SOUND_EXIT_SCREEN_WAV));
226 manager->Initialize(SOUND_ENTER_SCREEN,
227 bundle.GetRawDataResource(IDR_SOUND_ENTER_SCREEN_WAV));
dmazzoni16d2dec2016-12-19 23:27:57228 manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH,
229 bundle.GetRawDataResource(
230 IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH_WAV));
231 manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW,
232 bundle.GetRawDataResource(
233 IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW_WAV));
David Tseng580f050e2017-09-05 21:18:41234 manager->Initialize(SOUND_TOUCH_TYPE,
235 bundle.GetRawDataResource(IDR_SOUND_TOUCH_TYPE_WAV));
Zach Helfinsteinb89fef42018-04-12 21:38:54236 manager->Initialize(SOUND_DICTATION_END,
237 bundle.GetRawDataResource(IDR_SOUND_DICTATION_END_WAV));
238 manager->Initialize(SOUND_DICTATION_START,
239 bundle.GetRawDataResource(IDR_SOUND_DICTATION_START_WAV));
dmazzoni337c5af2016-09-13 23:08:57240
241 base::FilePath resources_path;
242 if (!PathService::Get(chrome::DIR_RESOURCES, &resources_path))
243 NOTREACHED();
244 chromevox_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
245 extension_misc::kChromeVoxExtensionId,
246 resources_path.Append(extension_misc::kChromeVoxExtensionPath),
247 base::Bind(&AccessibilityManager::PostUnloadChromeVox,
248 weak_ptr_factory_.GetWeakPtr())));
dmazzoni5288b2612016-09-16 23:05:39249 select_to_speak_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
250 extension_misc::kSelectToSpeakExtensionId,
251 resources_path.Append(extension_misc::kSelectToSpeakExtensionPath),
Katie D6264a8e2018-02-07 02:32:20252 base::Bind(&AccessibilityManager::PostUnloadSelectToSpeak,
253 weak_ptr_factory_.GetWeakPtr())));
elichtenberg0746c1bd2017-02-22 07:59:15254 switch_access_loader_ = base::WrapUnique(new AccessibilityExtensionLoader(
255 extension_misc::kSwitchAccessExtensionId,
256 resources_path.Append(extension_misc::kSwitchAccessExtensionPath),
257 base::Closure()));
Qiang Xu4e5853d382018-01-09 07:21:07258
259 // Connect to ash's AccessibilityController interface.
260 content::ServiceManagerConnection::GetForProcess()
261 ->GetConnector()
262 ->BindInterface(ash::mojom::kServiceName, &accessibility_controller_);
Qiang Xu56a75812018-03-15 00:28:34263
264 // Connect to ash's AccessibilityFocusRingController interface.
265 content::ServiceManagerConnection::GetForProcess()
266 ->GetConnector()
267 ->BindInterface(ash::mojom::kServiceName,
268 &accessibility_focus_ring_controller_);
[email protected]1dfebfc2013-06-04 03:14:32269}
270
271AccessibilityManager::~AccessibilityManager() {
272 CHECK(this == g_accessibility_manager);
Qiang Xu60e79032018-03-29 08:18:31273 AccessibilityStatusEventDetails details(ACCESSIBILITY_MANAGER_SHUTDOWN,
274 false);
[email protected]d8edc9c2014-02-25 00:06:03275 NotifyAccessibilityStatusChanged(details);
[email protected]1488a035f2014-03-28 21:12:07276 input_method::InputMethodManager::Get()->RemoveObserver(this);
tbarziccd5ad222017-03-24 04:46:31277 session_manager::SessionManager::Get()->RemoveObserver(this);
dmazzoni94a4f882015-11-13 05:46:52278
279 if (chromevox_panel_) {
James Cook769799b2018-03-12 16:59:04280 chromevox_panel_->CloseNow();
dmazzoni94a4f882015-11-13 05:46:52281 chromevox_panel_ = nullptr;
282 }
[email protected]1dfebfc2013-06-04 03:14:32283}
284
[email protected]c20122572013-12-16 20:35:58285bool AccessibilityManager::ShouldShowAccessibilityMenu() {
286 // If any of the loaded profiles has an accessibility feature turned on - or
287 // enforced to always show the menu - we return true to show the menu.
James Cookfc97f0a2017-08-16 20:05:35288 // NOTE: This includes the login screen profile, so if a feature is turned on
289 // at the login screen the menu will show even if the user has no features
290 // enabled inside the session. http://crbug.com/755631
[email protected]c20122572013-12-16 20:35:58291 std::vector<Profile*> profiles =
292 g_browser_process->profile_manager()->GetLoadedProfiles();
293 for (std::vector<Profile*>::iterator it = profiles.begin();
James Cook12ccadd2017-10-09 03:53:34294 it != profiles.end(); ++it) {
James Cookc63b9fd2017-08-18 18:48:32295 PrefService* prefs = (*it)->GetPrefs();
296 if (prefs->GetBoolean(ash::prefs::kAccessibilityStickyKeysEnabled) ||
297 prefs->GetBoolean(ash::prefs::kAccessibilityLargeCursorEnabled) ||
298 prefs->GetBoolean(ash::prefs::kAccessibilitySpokenFeedbackEnabled) ||
Katie D6af68c5e2018-02-14 23:21:16299 prefs->GetBoolean(ash::prefs::kAccessibilitySelectToSpeakEnabled) ||
James Cookc63b9fd2017-08-18 18:48:32300 prefs->GetBoolean(ash::prefs::kAccessibilityHighContrastEnabled) ||
301 prefs->GetBoolean(ash::prefs::kAccessibilityAutoclickEnabled) ||
302 prefs->GetBoolean(ash::prefs::kShouldAlwaysShowAccessibilityMenu) ||
303 prefs->GetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled) ||
304 prefs->GetBoolean(ash::prefs::kAccessibilityVirtualKeyboardEnabled) ||
305 prefs->GetBoolean(ash::prefs::kAccessibilityMonoAudioEnabled) ||
306 prefs->GetBoolean(ash::prefs::kAccessibilityCaretHighlightEnabled) ||
307 prefs->GetBoolean(ash::prefs::kAccessibilityCursorHighlightEnabled) ||
Ahmed Fakhry078927212018-04-06 20:59:09308 prefs->GetBoolean(ash::prefs::kAccessibilityFocusHighlightEnabled) ||
309 prefs->GetBoolean(ash::prefs::kDockedMagnifierEnabled)) {
[email protected]c20122572013-12-16 20:35:58310 return true;
Ahmed Fakhry078927212018-04-06 20:59:09311 }
[email protected]c20122572013-12-16 20:35:58312 }
313 return false;
314}
315
James Cookfc97f0a2017-08-16 20:05:35316void AccessibilityManager::UpdateAlwaysShowMenuFromPref() {
317 if (!profile_)
318 return;
319
James Cook696fb106a2017-08-17 21:50:44320 // TODO(crbug.com/594887): Fix for mash by moving pref into ash.
321 if (GetAshConfig() == ash::Config::MASH)
322 return;
323
James Cookfc97f0a2017-08-16 20:05:35324 // Update system tray menu visibility.
James Cook08e91dc2018-03-08 18:53:19325 ash::Shell::Get()
326 ->accessibility_controller()
Qiang Xu9c3bc702018-03-26 23:12:28327 ->NotifyAccessibilityStatusChanged();
James Cookfc97f0a2017-08-16 20:05:35328}
329
[email protected]8126b812013-06-06 03:49:17330void AccessibilityManager::EnableLargeCursor(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14331 if (!profile_)
332 return;
333
334 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32335 pref_service->SetBoolean(ash::prefs::kAccessibilityLargeCursorEnabled,
336 enabled);
[email protected]d80f19302013-06-07 13:12:14337 pref_service->CommitPendingWrite();
338}
339
James Cook9f9ff79d32017-09-01 00:39:29340void AccessibilityManager::OnLargeCursorChanged() {
jamescooka7f8dab2016-06-21 01:44:03341 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_LARGE_CURSOR,
Qiang Xu60e79032018-03-29 08:18:31342 IsLargeCursorEnabled());
[email protected]d8edc9c2014-02-25 00:06:03343 NotifyAccessibilityStatusChanged(details);
[email protected]8126b812013-06-06 03:49:17344}
345
minch0bfec0b2017-04-10 17:50:09346bool AccessibilityManager::IsLargeCursorEnabled() const {
James Cook9f9ff79d32017-09-01 00:39:29347 return profile_ && profile_->GetPrefs()->GetBoolean(
348 ash::prefs::kAccessibilityLargeCursorEnabled);
[email protected]8126b812013-06-06 03:49:17349}
350
[email protected]93a534e2013-06-20 16:41:44351void AccessibilityManager::EnableStickyKeys(bool enabled) {
352 if (!profile_)
353 return;
354 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32355 pref_service->SetBoolean(ash::prefs::kAccessibilityStickyKeysEnabled,
356 enabled);
[email protected]93a534e2013-06-20 16:41:44357 pref_service->CommitPendingWrite();
358}
359
minch0bfec0b2017-04-10 17:50:09360bool AccessibilityManager::IsStickyKeysEnabled() const {
Qiang Xu67fbc7a2018-02-16 02:52:41361 return profile_ && profile_->GetPrefs()->GetBoolean(
362 ash::prefs::kAccessibilityStickyKeysEnabled);
[email protected]93a534e2013-06-20 16:41:44363}
364
Qiang Xu67fbc7a2018-02-16 02:52:41365void AccessibilityManager::OnStickyKeysChanged() {
minchd9d542482017-04-07 19:29:56366 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_STICKY_KEYS,
Qiang Xu60e79032018-03-29 08:18:31367 IsStickyKeysEnabled());
minchd9d542482017-04-07 19:29:56368 NotifyAccessibilityStatusChanged(details);
[email protected]93a534e2013-06-20 16:41:44369}
370
Qiang Xu60e79032018-03-29 08:18:31371void AccessibilityManager::EnableSpokenFeedback(bool enabled) {
[email protected]1dfebfc2013-06-04 03:14:32372 if (!profile_)
373 return;
[email protected]5d2ea362013-12-13 08:10:18374
[email protected]1dfebfc2013-06-04 03:14:32375 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32376 pref_service->SetBoolean(ash::prefs::kAccessibilitySpokenFeedbackEnabled,
377 enabled);
[email protected]1dfebfc2013-06-04 03:14:32378 pref_service->CommitPendingWrite();
[email protected]d80f19302013-06-07 13:12:14379}
380
Qiang Xu8889e372018-01-12 02:04:42381void AccessibilityManager::OnSpokenFeedbackChanged() {
[email protected]d80f19302013-06-07 13:12:14382 if (!profile_)
383 return;
384
[email protected]ced247a2014-06-13 19:14:19385 const bool enabled = profile_->GetPrefs()->GetBoolean(
James Cookc63b9fd2017-08-18 18:48:32386 ash::prefs::kAccessibilitySpokenFeedbackEnabled);
[email protected]d80f19302013-06-07 13:12:14387
dmazzoni63199b12016-10-19 15:44:36388 if (enabled) {
389 chromevox_loader_->SetProfile(
390 profile_, base::Bind(&AccessibilityManager::PostSwitchChromeVoxProfile,
391 weak_ptr_factory_.GetWeakPtr()));
392 }
dmazzoni2c013202016-09-07 19:59:37393
Qiang(Joe) Xua0f644592017-12-01 02:16:50394 if (spoken_feedback_enabled_ == enabled)
395 return;
396
397 spoken_feedback_enabled_ = enabled;
398
James Cook12ccadd2017-10-09 03:53:34399 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK,
Qiang Xu60e79032018-03-29 08:18:31400 enabled);
[email protected]d8edc9c2014-02-25 00:06:03401 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32402
[email protected]0e9504d2013-11-05 02:33:29403 if (enabled) {
dtseng4702f8e2017-01-11 18:54:12404 chromevox_loader_->Load(profile_,
dmazzoni337c5af2016-09-13 23:08:57405 base::Bind(&AccessibilityManager::PostLoadChromeVox,
406 weak_ptr_factory_.GetWeakPtr()));
[email protected]0e9504d2013-11-05 02:33:29407 } else {
dmazzoni337c5af2016-09-13 23:08:57408 chromevox_loader_->Unload();
[email protected]0e9504d2013-11-05 02:33:29409 }
[email protected]2e5e0b12014-05-07 13:30:20410 UpdateBrailleImeState();
[email protected]b0a2ce32013-07-23 15:24:53411}
412
minch0bfec0b2017-04-10 17:50:09413bool AccessibilityManager::IsSpokenFeedbackEnabled() const {
Qiang Xu8889e372018-01-12 02:04:42414 return profile_ && profile_->GetPrefs()->GetBoolean(
415 ash::prefs::kAccessibilitySpokenFeedbackEnabled);
[email protected]1dfebfc2013-06-04 03:14:32416}
417
[email protected]1dfebfc2013-06-04 03:14:32418void AccessibilityManager::EnableHighContrast(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14419 if (!profile_)
420 return;
421
422 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32423 pref_service->SetBoolean(ash::prefs::kAccessibilityHighContrastEnabled,
424 enabled);
[email protected]d80f19302013-06-07 13:12:14425 pref_service->CommitPendingWrite();
426}
427
James Cook5fbdccb2017-09-01 21:17:55428bool AccessibilityManager::IsHighContrastEnabled() const {
429 return profile_ && profile_->GetPrefs()->GetBoolean(
430 ash::prefs::kAccessibilityHighContrastEnabled);
431}
[email protected]d80f19302013-06-07 13:12:14432
James Cook5fbdccb2017-09-01 21:17:55433void AccessibilityManager::OnHighContrastChanged() {
[email protected]d8edc9c2014-02-25 00:06:03434 AccessibilityStatusEventDetails details(
Qiang Xu60e79032018-03-29 08:18:31435 ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE, IsHighContrastEnabled());
[email protected]d8edc9c2014-02-25 00:06:03436 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32437}
438
[email protected]628b8902014-03-12 05:26:41439void AccessibilityManager::OnLocaleChanged() {
[email protected]d1d5f4f2013-06-14 07:17:09440 if (!profile_)
441 return;
442
443 if (!IsSpokenFeedbackEnabled())
444 return;
445
446 // If the system locale changes and spoken feedback is enabled,
447 // reload ChromeVox so that it switches its internal translations
448 // to the new language.
Qiang Xu60e79032018-03-29 08:18:31449 EnableSpokenFeedback(false);
450 EnableSpokenFeedback(true);
[email protected]d1d5f4f2013-06-14 07:17:09451}
452
yawanoca05a1af2017-01-25 02:38:17453void AccessibilityManager::OnViewFocusedInArc(
454 const gfx::Rect& bounds_in_screen) {
Qiang Xu95eea572018-02-17 08:10:31455 accessibility_controller_->SetFocusHighlightRect(bounds_in_screen);
yawanoca05a1af2017-01-25 02:38:17456}
457
sadrulcdc2bb42016-07-13 19:44:51458bool AccessibilityManager::PlayEarcon(int sound_key, PlaySoundOption option) {
[email protected]07f3ea92014-08-14 05:23:38459 DCHECK(sound_key < chromeos::SOUND_COUNT);
sadrulcdc2bb42016-07-13 19:44:51460 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
461 if (cl->HasSwitch(kAshDisableSystemSounds))
462 return false;
Qiang Xu89af823e2017-12-05 04:04:47463 if (option == PlaySoundOption::ONLY_IF_SPOKEN_FEEDBACK_ENABLED &&
David Tseng89850d12017-08-29 02:23:41464 !IsSpokenFeedbackEnabled()) {
sadrulcdc2bb42016-07-13 19:44:51465 return false;
466 }
467 return media::SoundsManager::Get()->Play(sound_key);
[email protected]07f3ea92014-08-14 05:23:38468}
469
dmazzonidf9a1e922017-04-13 05:10:44470void AccessibilityManager::OnTwoFingerTouchStart() {
dmazzonic613a562017-05-02 03:19:19471 if (!profile())
472 return;
473
dmazzonidf9a1e922017-04-13 05:10:44474 extensions::EventRouter* event_router =
475 extensions::EventRouter::Get(profile());
dmazzonidf9a1e922017-04-13 05:10:44476
Jinho Bang341ce5b02018-01-17 22:46:03477 auto event_args = std::make_unique<base::ListValue>();
478 auto event = std::make_unique<extensions::Event>(
dmazzonidf9a1e922017-04-13 05:10:44479 extensions::events::ACCESSIBILITY_PRIVATE_ON_TWO_FINGER_TOUCH_START,
480 extensions::api::accessibility_private::OnTwoFingerTouchStart::kEventName,
481 std::move(event_args));
482 event_router->BroadcastEvent(std::move(event));
483}
484
485void AccessibilityManager::OnTwoFingerTouchStop() {
dmazzonic613a562017-05-02 03:19:19486 if (!profile())
487 return;
488
dmazzonidf9a1e922017-04-13 05:10:44489 extensions::EventRouter* event_router =
490 extensions::EventRouter::Get(profile());
dmazzonidf9a1e922017-04-13 05:10:44491
Jinho Bang341ce5b02018-01-17 22:46:03492 auto event_args = std::make_unique<base::ListValue>();
493 auto event = std::make_unique<extensions::Event>(
dmazzonidf9a1e922017-04-13 05:10:44494 extensions::events::ACCESSIBILITY_PRIVATE_ON_TWO_FINGER_TOUCH_STOP,
495 extensions::api::accessibility_private::OnTwoFingerTouchStop::kEventName,
496 std::move(event_args));
497 event_router->BroadcastEvent(std::move(event));
498}
499
dmazzoni16d2dec2016-12-19 23:27:57500bool AccessibilityManager::ShouldToggleSpokenFeedbackViaTouch() {
dmazzoni200099c2017-01-31 23:21:40501#if 1
502 // Temporarily disabling this feature until UI feedback is fixed.
503 // http://crbug.com/662501
504 return false;
505#else
dmazzoni16d2dec2016-12-19 23:27:57506 policy::BrowserPolicyConnectorChromeOS* connector =
507 g_browser_process->platform_part()->browser_policy_connector_chromeos();
508 if (!connector)
509 return false;
510
511 if (!connector->IsEnterpriseManaged())
512 return false;
513
514 const policy::DeviceCloudPolicyManagerChromeOS* const
515 device_cloud_policy_manager = connector->GetDeviceCloudPolicyManager();
516 if (!device_cloud_policy_manager)
517 return false;
518
519 if (!device_cloud_policy_manager->IsRemoraRequisition())
520 return false;
521
522 KioskAppManager* manager = KioskAppManager::Get();
523 KioskAppManager::App app;
524 CHECK(manager->GetApp(manager->GetAutoLaunchApp(), &app));
525 return app.was_auto_launched_with_zero_delay;
dmazzoni200099c2017-01-31 23:21:40526#endif
dmazzoni16d2dec2016-12-19 23:27:57527}
528
529bool AccessibilityManager::PlaySpokenFeedbackToggleCountdown(int tick_count) {
530 return media::SoundsManager::Get()->Play(
531 tick_count % 2 ? SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH
532 : SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW);
533}
534
Qiang Xu9e12fa762017-12-19 03:27:49535void AccessibilityManager::HandleAccessibilityGesture(
Qiang Xuc4b05752018-02-13 20:10:28536 ax::mojom::Gesture gesture) {
dmazzoni82ef29a2016-05-10 23:37:51537 extensions::EventRouter* event_router =
538 extensions::EventRouter::Get(profile());
dmazzoni82ef29a2016-05-10 23:37:51539
Katie D30e08412018-05-02 17:24:22540 std::unique_ptr<base::ListValue> event_args =
541 std::make_unique<base::ListValue>();
Qiang Xuc4b05752018-02-13 20:10:28542 event_args->AppendString(ui::ToString(gesture));
dmazzoni82ef29a2016-05-10 23:37:51543 std::unique_ptr<extensions::Event> event(new extensions::Event(
544 extensions::events::ACCESSIBILITY_PRIVATE_ON_ACCESSIBILITY_GESTURE,
545 extensions::api::accessibility_private::OnAccessibilityGesture::
546 kEventName,
547 std::move(event_args)));
548 event_router->DispatchEventWithLazyListener(
549 extension_misc::kChromeVoxExtensionId, std::move(event));
550}
551
dmazzoniff86e3472016-06-03 19:52:32552void AccessibilityManager::SetTouchAccessibilityAnchorPoint(
553 const gfx::Point& anchor_point) {
dmazzoni50f65802017-06-28 18:19:39554 for (auto* rwc : ash::RootWindowController::root_window_controllers())
555 rwc->SetTouchAccessibilityAnchorPoint(anchor_point);
dmazzoniff86e3472016-06-03 19:52:32556}
557
[email protected]1c881562013-10-12 07:52:58558void AccessibilityManager::EnableAutoclick(bool enabled) {
559 if (!profile_)
560 return;
561
562 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32563 pref_service->SetBoolean(ash::prefs::kAccessibilityAutoclickEnabled, enabled);
[email protected]1c881562013-10-12 07:52:58564 pref_service->CommitPendingWrite();
565}
566
minch0bfec0b2017-04-10 17:50:09567bool AccessibilityManager::IsAutoclickEnabled() const {
Qiang Xud0f3be2e2018-01-08 12:48:18568 return profile_ && profile_->GetPrefs()->GetBoolean(
569 ash::prefs::kAccessibilityAutoclickEnabled);
[email protected]1c881562013-10-12 07:52:58570}
571
[email protected]e1b299b2014-01-29 23:53:41572void AccessibilityManager::EnableVirtualKeyboard(bool enabled) {
573 if (!profile_)
574 return;
575
576 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32577 pref_service->SetBoolean(ash::prefs::kAccessibilityVirtualKeyboardEnabled,
[email protected]ced247a2014-06-13 19:14:19578 enabled);
[email protected]e1b299b2014-01-29 23:53:41579 pref_service->CommitPendingWrite();
580}
581
minch0bfec0b2017-04-10 17:50:09582bool AccessibilityManager::IsVirtualKeyboardEnabled() const {
Qiang Xu67fbc7a2018-02-16 02:52:41583 return profile_ && profile_->GetPrefs()->GetBoolean(
584 ash::prefs::kAccessibilityVirtualKeyboardEnabled);
[email protected]e1b299b2014-01-29 23:53:41585}
586
Qiang Xu67fbc7a2018-02-16 02:52:41587void AccessibilityManager::OnVirtualKeyboardChanged() {
jamescooka7f8dab2016-06-21 01:44:03588 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_VIRTUAL_KEYBOARD,
Qiang Xu60e79032018-03-29 08:18:31589 IsVirtualKeyboardEnabled());
rsadama1104b82014-11-03 20:50:52590 NotifyAccessibilityStatusChanged(details);
[email protected]e1b299b2014-01-29 23:53:41591}
592
warx533c8f62016-04-12 01:19:43593void AccessibilityManager::EnableMonoAudio(bool enabled) {
594 if (!profile_)
595 return;
596
597 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32598 pref_service->SetBoolean(ash::prefs::kAccessibilityMonoAudioEnabled, enabled);
warx533c8f62016-04-12 01:19:43599 pref_service->CommitPendingWrite();
600}
601
minch0bfec0b2017-04-10 17:50:09602bool AccessibilityManager::IsMonoAudioEnabled() const {
Qiang Xu1ee98022017-11-21 19:52:55603 return profile_ && profile_->GetPrefs()->GetBoolean(
604 ash::prefs::kAccessibilityMonoAudioEnabled);
warx533c8f62016-04-12 01:19:43605}
606
Qiang Xu1ee98022017-11-21 19:52:55607void AccessibilityManager::OnMonoAudioChanged() {
jamescooka7f8dab2016-06-21 01:44:03608 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_MONO_AUDIO,
Qiang Xu60e79032018-03-29 08:18:31609 IsMonoAudioEnabled());
warx533c8f62016-04-12 01:19:43610 NotifyAccessibilityStatusChanged(details);
warx533c8f62016-04-12 01:19:43611}
612
Daniel Erat477c56d2017-12-13 21:42:54613void AccessibilityManager::SetDarkenScreen(bool darken) {
Qiang Xu4e5853d382018-01-09 07:21:07614 accessibility_controller_->SetDarkenScreen(darken);
Daniel Erat477c56d2017-12-13 21:42:54615}
616
dmazzoni756089a22016-03-15 23:55:16617void AccessibilityManager::SetCaretHighlightEnabled(bool enabled) {
618 if (!profile_)
619 return;
620
621 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32622 pref_service->SetBoolean(ash::prefs::kAccessibilityCaretHighlightEnabled,
623 enabled);
dmazzoni756089a22016-03-15 23:55:16624 pref_service->CommitPendingWrite();
625}
626
627bool AccessibilityManager::IsCaretHighlightEnabled() const {
Qiang Xu95eea572018-02-17 08:10:31628 return profile_ && profile_->GetPrefs()->GetBoolean(
629 ash::prefs::kAccessibilityCaretHighlightEnabled);
dmazzoni756089a22016-03-15 23:55:16630}
631
Qiang Xu95eea572018-02-17 08:10:31632void AccessibilityManager::OnCaretHighlightChanged() {
mincha0b24ab2017-03-31 22:16:01633 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_CARET_HIGHLIGHT,
Qiang Xu60e79032018-03-29 08:18:31634 IsCaretHighlightEnabled());
mincha0b24ab2017-03-31 22:16:01635 NotifyAccessibilityStatusChanged(details);
dmazzoni756089a22016-03-15 23:55:16636}
637
638void AccessibilityManager::SetCursorHighlightEnabled(bool enabled) {
639 if (!profile_)
640 return;
641
642 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32643 pref_service->SetBoolean(ash::prefs::kAccessibilityCursorHighlightEnabled,
dmazzoni756089a22016-03-15 23:55:16644 enabled);
645 pref_service->CommitPendingWrite();
646}
647
648bool AccessibilityManager::IsCursorHighlightEnabled() const {
Qiang Xu95eea572018-02-17 08:10:31649 return profile_ && profile_->GetPrefs()->GetBoolean(
650 ash::prefs::kAccessibilityCursorHighlightEnabled);
dmazzoni756089a22016-03-15 23:55:16651}
652
Qiang Xu95eea572018-02-17 08:10:31653void AccessibilityManager::OnCursorHighlightChanged() {
mincha0b24ab2017-03-31 22:16:01654 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_CURSOR_HIGHLIGHT,
Qiang Xu60e79032018-03-29 08:18:31655 IsCursorHighlightEnabled());
mincha0b24ab2017-03-31 22:16:01656 NotifyAccessibilityStatusChanged(details);
dmazzoni756089a22016-03-15 23:55:16657}
658
659void AccessibilityManager::SetFocusHighlightEnabled(bool enabled) {
660 if (!profile_)
661 return;
662
663 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32664 pref_service->SetBoolean(ash::prefs::kAccessibilityFocusHighlightEnabled,
665 enabled);
dmazzoni756089a22016-03-15 23:55:16666 pref_service->CommitPendingWrite();
667}
668
669bool AccessibilityManager::IsFocusHighlightEnabled() const {
Qiang Xu95eea572018-02-17 08:10:31670 return profile_ && profile_->GetPrefs()->GetBoolean(
671 ash::prefs::kAccessibilityFocusHighlightEnabled);
dmazzoni756089a22016-03-15 23:55:16672}
673
Qiang Xu95eea572018-02-17 08:10:31674void AccessibilityManager::OnFocusHighlightChanged() {
675 bool enabled = IsFocusHighlightEnabled();
dmazzoni756089a22016-03-15 23:55:16676
dmazzoni42e4b002016-06-08 20:58:42677 // Focus highlighting can't be on when spoken feedback is on, because
678 // ChromeVox does its own focus highlighting.
Qiang Xu95eea572018-02-17 08:10:31679 if (IsSpokenFeedbackEnabled())
dmazzoni42e4b002016-06-08 20:58:42680 enabled = false;
mincha0b24ab2017-03-31 22:16:01681 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_FOCUS_HIGHLIGHT,
Qiang Xu60e79032018-03-29 08:18:31682 enabled);
mincha0b24ab2017-03-31 22:16:01683 NotifyAccessibilityStatusChanged(details);
dmazzoni756089a22016-03-15 23:55:16684}
685
dmazzoni756089a22016-03-15 23:55:16686void AccessibilityManager::SetSelectToSpeakEnabled(bool enabled) {
687 if (!profile_)
688 return;
689
690 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32691 pref_service->SetBoolean(ash::prefs::kAccessibilitySelectToSpeakEnabled,
692 enabled);
dmazzoni756089a22016-03-15 23:55:16693 pref_service->CommitPendingWrite();
694}
695
696bool AccessibilityManager::IsSelectToSpeakEnabled() const {
697 return select_to_speak_enabled_;
698}
699
Katie D30e08412018-05-02 17:24:22700void AccessibilityManager::RequestSelectToSpeakStateChange() {
701 extensions::EventRouter* event_router =
702 extensions::EventRouter::Get(profile_);
703
704 // Send an event to the Select-to-Speak extension requesting a state change.
705 std::unique_ptr<base::ListValue> event_args =
706 std::make_unique<base::ListValue>();
707 std::unique_ptr<extensions::Event> event(new extensions::Event(
708 extensions::events::
709 ACCESSIBILITY_PRIVATE_ON_SELECT_TO_SPEAK_STATE_CHANGE_REQUESTED,
710 extensions::api::accessibility_private::
711 OnSelectToSpeakStateChangeRequested::kEventName,
712 std::move(event_args)));
713 event_router->DispatchEventWithLazyListener(
714 extension_misc::kSelectToSpeakExtensionId, std::move(event));
715}
716
717void AccessibilityManager::OnSelectToSpeakStateChanged(
718 ash::mojom::SelectToSpeakState state) {
Katie Dae8cce52018-05-02 21:16:28719 // Forward the state change event to select_to_speak_event_handler_.
720 // The extension may have requested that the handler enter SELECTING state.
721 // Prepare to start capturing events from stylus, mouse or touch.
722 if (select_to_speak_event_handler_) {
723 select_to_speak_event_handler_->SetSelectToSpeakStateSelecting(
724 state == ash::mojom::SelectToSpeakState::kSelectToSpeakStateSelecting);
725 }
Katie D30e08412018-05-02 17:24:22726
727 accessibility_controller_->SetSelectToSpeakState(state);
728}
729
Katie D6af68c5e2018-02-14 23:21:16730void AccessibilityManager::OnSelectToSpeakChanged() {
dmazzoni756089a22016-03-15 23:55:16731 if (!profile_)
732 return;
733
734 const bool enabled = profile_->GetPrefs()->GetBoolean(
James Cookc63b9fd2017-08-18 18:48:32735 ash::prefs::kAccessibilitySelectToSpeakEnabled);
dmazzoni756089a22016-03-15 23:55:16736
737 if (select_to_speak_enabled_ == enabled)
738 return;
739 select_to_speak_enabled_ = enabled;
740
Katie D6af68c5e2018-02-14 23:21:16741 AccessibilityStatusEventDetails details(ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK,
Qiang Xu60e79032018-03-29 08:18:31742 enabled);
Katie D6af68c5e2018-02-14 23:21:16743 NotifyAccessibilityStatusChanged(details);
744
Katie D4ea69442018-04-02 23:17:30745 if (enabled) {
dtseng4702f8e2017-01-11 18:54:12746 select_to_speak_loader_->Load(profile_, base::Closure() /* done_cb */);
Katie D4ea69442018-04-02 23:17:30747 select_to_speak_event_handler_.reset(
748 new chromeos::SelectToSpeakEventHandler());
749 } else {
dmazzoni5288b2612016-09-16 23:05:39750 select_to_speak_loader_->Unload();
Katie D4ea69442018-04-02 23:17:30751 select_to_speak_event_handler_.reset(nullptr);
752 }
dmazzoni756089a22016-03-15 23:55:16753}
754
755void AccessibilityManager::SetSwitchAccessEnabled(bool enabled) {
756 if (!profile_)
757 return;
758
759 PrefService* pref_service = profile_->GetPrefs();
James Cookc63b9fd2017-08-18 18:48:32760 pref_service->SetBoolean(ash::prefs::kAccessibilitySwitchAccessEnabled,
761 enabled);
dmazzoni756089a22016-03-15 23:55:16762 pref_service->CommitPendingWrite();
763}
764
765bool AccessibilityManager::IsSwitchAccessEnabled() const {
766 return switch_access_enabled_;
767}
768
769void AccessibilityManager::UpdateSwitchAccessFromPref() {
770 if (!profile_)
771 return;
772
773 const bool enabled = profile_->GetPrefs()->GetBoolean(
James Cookc63b9fd2017-08-18 18:48:32774 ash::prefs::kAccessibilitySwitchAccessEnabled);
dmazzoni756089a22016-03-15 23:55:16775
Dominic Mazzonic85a5c92017-08-31 18:53:30776 // The Switch Access setting is behind a flag. Don't enable the feature
777 // even if the preference is enabled, if the flag isn't also set.
778 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
779 if (!command_line->HasSwitch(
780 chromeos::switches::kEnableExperimentalAccessibilityFeatures)) {
781 if (enabled) {
782 LOG(WARNING) << "Switch access enabled but experimental accessibility "
783 << "features flag is not set.";
784 }
785 return;
786 }
787
dmazzoni756089a22016-03-15 23:55:16788 if (switch_access_enabled_ == enabled)
789 return;
790 switch_access_enabled_ = enabled;
791
elichtenberg0746c1bd2017-02-22 07:59:15792 if (enabled) {
793 switch_access_loader_->Load(profile_, base::Closure() /* done_cb */);
elichtenbergc4b4bf462017-02-28 20:48:10794 switch_access_event_handler_.reset(
795 new chromeos::SwitchAccessEventHandler());
elichtenberg0746c1bd2017-02-22 07:59:15796 } else {
797 switch_access_loader_->Unload();
elichtenbergc4b4bf462017-02-28 20:48:10798 switch_access_event_handler_.reset(nullptr);
elichtenberg0746c1bd2017-02-22 07:59:15799 }
dmazzoni756089a22016-03-15 23:55:16800}
801
[email protected]a81b2c32014-03-28 06:35:01802bool AccessibilityManager::IsBrailleDisplayConnected() const {
803 return braille_display_connected_;
804}
805
[email protected]8c79e3f2013-10-30 01:05:14806void AccessibilityManager::CheckBrailleState() {
[email protected]a81b2c32014-03-28 06:35:01807 BrailleController* braille_controller = GetBrailleController();
808 if (!scoped_braille_observer_.IsObserving(braille_controller))
809 scoped_braille_observer_.Add(braille_controller);
[email protected]8c79e3f2013-10-30 01:05:14810 BrowserThread::PostTaskAndReplyWithResult(
James Cook12ccadd2017-10-09 03:53:34811 BrowserThread::IO, FROM_HERE,
[email protected]a81b2c32014-03-28 06:35:01812 base::Bind(&BrailleController::GetDisplayState,
813 base::Unretained(braille_controller)),
[email protected]8c79e3f2013-10-30 01:05:14814 base::Bind(&AccessibilityManager::ReceiveBrailleDisplayState,
815 weak_ptr_factory_.GetWeakPtr()));
816}
817
818void AccessibilityManager::ReceiveBrailleDisplayState(
dcheng24002d02016-04-08 02:42:40819 std::unique_ptr<extensions::api::braille_display_private::DisplayState>
820 state) {
[email protected]2e5e0b12014-05-07 13:30:20821 OnBrailleDisplayStateChanged(*state);
822}
823
824void AccessibilityManager::UpdateBrailleImeState() {
825 if (!profile_)
826 return;
827 PrefService* pref_service = profile_->GetPrefs();
mgiuca30f75882017-03-28 02:07:19828 std::string preload_engines_str =
829 pref_service->GetString(prefs::kLanguagePreloadEngines);
830 std::vector<base::StringPiece> preload_engines = base::SplitStringPiece(
831 preload_engines_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
832 std::vector<base::StringPiece>::iterator it =
833 std::find(preload_engines.begin(), preload_engines.end(),
jamescook2d60f032017-06-01 00:55:21834 extension_ime_util::kBrailleImeEngineId);
[email protected]2e5e0b12014-05-07 13:30:20835 bool is_enabled = (it != preload_engines.end());
836 bool should_be_enabled =
Qiang Xu8889e372018-01-12 02:04:42837 (IsSpokenFeedbackEnabled() && braille_display_connected_);
[email protected]2e5e0b12014-05-07 13:30:20838 if (is_enabled == should_be_enabled)
839 return;
840 if (should_be_enabled)
jamescook2d60f032017-06-01 00:55:21841 preload_engines.push_back(extension_ime_util::kBrailleImeEngineId);
[email protected]2e5e0b12014-05-07 13:30:20842 else
843 preload_engines.erase(it);
844 pref_service->SetString(prefs::kLanguagePreloadEngines,
brettwd94a22142015-07-15 05:19:26845 base::JoinString(preload_engines, ","));
[email protected]2e5e0b12014-05-07 13:30:20846 braille_ime_current_ = false;
[email protected]8c79e3f2013-10-30 01:05:14847}
848
[email protected]1488a035f2014-03-28 21:12:07849// Overridden from InputMethodManager::Observer.
850void AccessibilityManager::InputMethodChanged(
851 input_method::InputMethodManager* manager,
alematef06730292015-05-12 21:36:07852 Profile* /* profile */,
[email protected]1488a035f2014-03-28 21:12:07853 bool show_message) {
[email protected]1488a035f2014-03-28 21:12:07854 // Sticky keys is implemented only in ash.
dpolukhin04e5b8092014-09-11 02:55:05855 // TODO(dpolukhin): support Athena, crbug.com/408733.
James Cook696fb106a2017-08-17 21:50:44856 if (GetAshConfig() != ash::Config::MASH) {
skycb4be5b2017-04-06 17:52:45857 ash::Shell::Get()->sticky_keys_controller()->SetModifiersEnabled(
riajiang4b626b972016-09-13 16:12:49858 manager->IsISOLevel5ShiftUsedByCurrentInputMethod(),
859 manager->IsAltGrUsedByCurrentInputMethod());
860 }
[email protected]2e5e0b12014-05-07 13:30:20861 const chromeos::input_method::InputMethodDescriptor descriptor =
[email protected]f0881cf2014-08-15 23:31:42862 manager->GetActiveIMEState()->GetCurrentInputMethod();
[email protected]2e5e0b12014-05-07 13:30:20863 braille_ime_current_ =
jamescook2d60f032017-06-01 00:55:21864 (descriptor.id() == extension_ime_util::kBrailleImeEngineId);
[email protected]1488a035f2014-03-28 21:12:07865}
[email protected]8c79e3f2013-10-30 01:05:14866
tbarziccd5ad222017-03-24 04:46:31867void AccessibilityManager::OnSessionStateChanged() {
James Cook0c4f37ac02018-01-17 02:17:09868 // Don't reload ChromeVox during shutdown. http://crrev.com/c/838180
869 if (app_terminating_)
870 return;
871
tbarziccd5ad222017-03-24 04:46:31872 if (!chromevox_panel_)
873 return;
874 if (chromevox_panel_->for_blocked_user_session() ==
875 session_manager::SessionManager::Get()->IsUserSessionBlocked()) {
876 return;
877 }
878
879 // If user session got blocked or unblocked, reload ChromeVox panel, as
880 // functionality available to the panel differs based on whether the user
881 // session is active (and unlocked) or not.
882 ReloadChromeVoxPanel();
883}
884
[email protected]1dfebfc2013-06-04 03:14:32885void AccessibilityManager::SetProfile(Profile* profile) {
Yuki Awanod59b6492017-07-28 00:52:11886 // Do nothing if this is called for the current profile. This can happen. For
887 // example, ChromeSessionManager fires both
888 // NOTIFICATION_LOGIN_USER_PROFILE_PREPARED and NOTIFICATION_SESSION_STARTED,
889 // and we are observing both events.
890 if (profile_ == profile)
891 return;
892
[email protected]1dfebfc2013-06-04 03:14:32893 pref_change_registrar_.reset();
[email protected]d1d5f4f2013-06-14 07:17:09894 local_state_pref_change_registrar_.reset();
[email protected]1dfebfc2013-06-04 03:14:32895
David Tseng8a5de492018-01-17 20:41:37896 // Clear all dictation state on profile change.
897 dictation_.reset();
898
[email protected]1dfebfc2013-06-04 03:14:32899 if (profile) {
[email protected]0aae2fe2013-07-05 07:04:42900 // TODO(yoshiki): Move following code to PrefHandler.
[email protected]1dfebfc2013-06-04 03:14:32901 pref_change_registrar_.reset(new PrefChangeRegistrar);
902 pref_change_registrar_->Init(profile->GetPrefs());
903 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32904 ash::prefs::kShouldAlwaysShowAccessibilityMenu,
James Cookfc97f0a2017-08-16 20:05:35905 base::Bind(&AccessibilityManager::UpdateAlwaysShowMenuFromPref,
906 base::Unretained(this)));
907 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32908 ash::prefs::kAccessibilityLargeCursorEnabled,
James Cook9f9ff79d32017-09-01 00:39:29909 base::Bind(&AccessibilityManager::OnLargeCursorChanged,
[email protected]8126b812013-06-06 03:49:17910 base::Unretained(this)));
911 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32912 ash::prefs::kAccessibilityLargeCursorDipSize,
James Cook9f9ff79d32017-09-01 00:39:29913 base::Bind(&AccessibilityManager::OnLargeCursorChanged,
yawanodc5533b32017-02-23 11:04:38914 base::Unretained(this)));
915 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32916 ash::prefs::kAccessibilityStickyKeysEnabled,
Qiang Xu67fbc7a2018-02-16 02:52:41917 base::Bind(&AccessibilityManager::OnStickyKeysChanged,
[email protected]93a534e2013-06-20 16:41:44918 base::Unretained(this)));
919 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32920 ash::prefs::kAccessibilitySpokenFeedbackEnabled,
Qiang Xu8889e372018-01-12 02:04:42921 base::Bind(&AccessibilityManager::OnSpokenFeedbackChanged,
[email protected]1dfebfc2013-06-04 03:14:32922 base::Unretained(this)));
923 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32924 ash::prefs::kAccessibilityHighContrastEnabled,
James Cook5fbdccb2017-09-01 21:17:55925 base::Bind(&AccessibilityManager::OnHighContrastChanged,
[email protected]1dfebfc2013-06-04 03:14:32926 base::Unretained(this)));
[email protected]1c881562013-10-12 07:52:58927 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32928 ash::prefs::kAccessibilityVirtualKeyboardEnabled,
Qiang Xu67fbc7a2018-02-16 02:52:41929 base::Bind(&AccessibilityManager::OnVirtualKeyboardChanged,
[email protected]e1b299b2014-01-29 23:53:41930 base::Unretained(this)));
dmazzoni756089a22016-03-15 23:55:16931 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32932 ash::prefs::kAccessibilityMonoAudioEnabled,
Qiang Xu1ee98022017-11-21 19:52:55933 base::Bind(&AccessibilityManager::OnMonoAudioChanged,
warx533c8f62016-04-12 01:19:43934 base::Unretained(this)));
935 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32936 ash::prefs::kAccessibilityCaretHighlightEnabled,
Qiang Xu95eea572018-02-17 08:10:31937 base::Bind(&AccessibilityManager::OnCaretHighlightChanged,
dmazzoni756089a22016-03-15 23:55:16938 base::Unretained(this)));
939 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32940 ash::prefs::kAccessibilityCursorHighlightEnabled,
Qiang Xu95eea572018-02-17 08:10:31941 base::Bind(&AccessibilityManager::OnCursorHighlightChanged,
dmazzoni756089a22016-03-15 23:55:16942 base::Unretained(this)));
943 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32944 ash::prefs::kAccessibilityFocusHighlightEnabled,
Qiang Xu95eea572018-02-17 08:10:31945 base::Bind(&AccessibilityManager::OnFocusHighlightChanged,
dmazzoni756089a22016-03-15 23:55:16946 base::Unretained(this)));
947 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32948 ash::prefs::kAccessibilitySelectToSpeakEnabled,
Katie D6af68c5e2018-02-14 23:21:16949 base::Bind(&AccessibilityManager::OnSelectToSpeakChanged,
dmazzoni756089a22016-03-15 23:55:16950 base::Unretained(this)));
951 pref_change_registrar_->Add(
James Cookc63b9fd2017-08-18 18:48:32952 ash::prefs::kAccessibilitySwitchAccessEnabled,
dmazzoni756089a22016-03-15 23:55:16953 base::Bind(&AccessibilityManager::UpdateSwitchAccessFromPref,
954 base::Unretained(this)));
[email protected]1dfebfc2013-06-04 03:14:32955
[email protected]d1d5f4f2013-06-14 07:17:09956 local_state_pref_change_registrar_.reset(new PrefChangeRegistrar);
957 local_state_pref_change_registrar_->Init(g_browser_process->local_state());
958 local_state_pref_change_registrar_->Add(
959 prefs::kApplicationLocale,
[email protected]628b8902014-03-12 05:26:41960 base::Bind(&AccessibilityManager::OnLocaleChanged,
[email protected]d1d5f4f2013-06-14 07:17:09961 base::Unretained(this)));
962
[email protected]1dfebfc2013-06-04 03:14:32963 content::BrowserAccessibilityState::GetInstance()->AddHistogramCallback(
James Cook12ccadd2017-10-09 03:53:34964 base::Bind(&AccessibilityManager::UpdateChromeOSAccessibilityHistograms,
965 base::Unretained(this)));
dmazzoni337c5af2016-09-13 23:08:57966
dmazzoni337c5af2016-09-13 23:08:57967 extensions::ExtensionRegistry* registry =
968 extensions::ExtensionRegistry::Get(profile);
969 if (!extension_registry_observer_.IsObserving(registry))
970 extension_registry_observer_.Add(registry);
[email protected]1dfebfc2013-06-04 03:14:32971 }
972
[email protected]a81b2c32014-03-28 06:35:01973 bool had_profile = (profile_ != NULL);
974 profile_ = profile;
975
976 if (!had_profile && profile)
[email protected]8c79e3f2013-10-30 01:05:14977 CheckBrailleState();
[email protected]2e5e0b12014-05-07 13:30:20978 else
979 UpdateBrailleImeState();
James Cookfc97f0a2017-08-16 20:05:35980 UpdateAlwaysShowMenuFromPref();
dmazzoni756089a22016-03-15 23:55:16981 UpdateSwitchAccessFromPref();
dmazzoni39d6d4b2016-03-29 22:18:00982
Qiang Xu8889e372018-01-12 02:04:42983 // TODO(warx): reconcile to ash once the prefs registration above is moved to
984 // ash.
985 OnSpokenFeedbackChanged();
Katie D6af68c5e2018-02-14 23:21:16986 OnSelectToSpeakChanged();
[email protected]1dfebfc2013-06-04 03:14:32987}
988
xiyuan5d8d3ba2017-03-01 21:34:40989void AccessibilityManager::ActiveUserChanged(
990 const user_manager::User* active_user) {
xiyuan8c6a4112017-06-19 21:03:49991 if (active_user && active_user->is_profile_created())
992 SetProfile(ProfileManager::GetActiveUserProfile());
[email protected]c20122572013-12-16 20:35:58993}
994
[email protected]ce89d9392013-12-11 21:05:20995base::TimeDelta AccessibilityManager::PlayShutdownSound() {
Qiang Xu89af823e2017-12-05 04:04:47996 if (!PlayEarcon(SOUND_SHUTDOWN,
997 PlaySoundOption::ONLY_IF_SPOKEN_FEEDBACK_ENABLED)) {
[email protected]4f011f12014-01-15 08:22:45998 return base::TimeDelta();
Qiang Xu89af823e2017-12-05 04:04:47999 }
[email protected]4f011f12014-01-15 08:22:451000 return media::SoundsManager::Get()->GetDuration(SOUND_SHUTDOWN);
[email protected]ce89d9392013-12-11 21:05:201001}
1002
dcheng24002d02016-04-08 02:42:401003std::unique_ptr<AccessibilityStatusSubscription>
1004AccessibilityManager::RegisterCallback(const AccessibilityStatusCallback& cb) {
[email protected]d8edc9c2014-02-25 00:06:031005 return callback_list_.Add(cb);
1006}
1007
1008void AccessibilityManager::NotifyAccessibilityStatusChanged(
Qiang Xu56a75812018-03-15 00:28:341009 const AccessibilityStatusEventDetails& details) {
[email protected]d8edc9c2014-02-25 00:06:031010 callback_list_.Notify(details);
James Cookfc97f0a2017-08-16 20:05:351011
James Cook696fb106a2017-08-17 21:50:441012 // TODO(crbug.com/594887): Fix for mash by moving pref into ash.
1013 if (GetAshConfig() == ash::Config::MASH)
1014 return;
1015
Zach Helfinsteinbbb6bad2018-05-02 18:21:511016 if (details.notification_type == ACCESSIBILITY_TOGGLE_DICTATION) {
1017 ash::Shell::Get()->accessibility_controller()->SetDictationActive(
1018 details.enabled);
1019 ash::Shell::Get()
1020 ->accessibility_controller()
1021 ->NotifyAccessibilityStatusChanged();
1022 return;
1023 }
1024
James Cookec144952017-09-01 00:05:161025 // Update system tray menu visibility. Prefs tracked inside ash handle their
1026 // own updates to avoid race conditions (pref updates are asynchronous between
1027 // chrome and ash).
Zach Helfinsteinbbb6bad2018-05-02 18:21:511028 if (details.notification_type == ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER ||
1029 details.notification_type == ACCESSIBILITY_TOGGLE_DICTATION) {
James Cook08e91dc2018-03-08 18:53:191030 ash::Shell::Get()
1031 ->accessibility_controller()
Qiang Xu9c3bc702018-03-26 23:12:281032 ->NotifyAccessibilityStatusChanged();
James Cookfc97f0a2017-08-16 20:05:351033 }
[email protected]d8edc9c2014-02-25 00:06:031034}
1035
[email protected]1dfebfc2013-06-04 03:14:321036void AccessibilityManager::UpdateChromeOSAccessibilityHistograms() {
1037 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSpokenFeedback",
1038 IsSpokenFeedbackEnabled());
1039 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosHighContrast",
1040 IsHighContrastEnabled());
1041 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosVirtualKeyboard",
[email protected]e1b299b2014-01-29 23:53:411042 IsVirtualKeyboardEnabled());
[email protected]7fb7ea42014-02-12 21:19:311043 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosStickyKeys", IsStickyKeysEnabled());
[email protected]1dfebfc2013-06-04 03:14:321044 if (MagnificationManager::Get()) {
James Cookdb81c7672017-08-30 15:18:241045 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosScreenMagnifier",
1046 MagnificationManager::Get()->IsMagnifierEnabled());
[email protected]1dfebfc2013-06-04 03:14:321047 }
[email protected]ca3a0a82013-06-18 06:52:121048 if (profile_) {
1049 const PrefService* const prefs = profile_->GetPrefs();
yawano0c3441c72017-04-11 01:09:161050
1051 bool large_cursor_enabled =
James Cookc63b9fd2017-08-18 18:48:321052 prefs->GetBoolean(ash::prefs::kAccessibilityLargeCursorEnabled);
yawano0c3441c72017-04-11 01:09:161053 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosLargeCursor",
1054 large_cursor_enabled);
yawano92daff52017-04-21 06:34:281055 if (large_cursor_enabled) {
yawano0c3441c72017-04-11 01:09:161056 UMA_HISTOGRAM_COUNTS_100(
1057 "Accessibility.CrosLargeCursorSize",
James Cookc63b9fd2017-08-18 18:48:321058 prefs->GetInteger(ash::prefs::kAccessibilityLargeCursorDipSize));
yawano0c3441c72017-04-11 01:09:161059 }
1060
[email protected]ca3a0a82013-06-18 06:52:121061 UMA_HISTOGRAM_BOOLEAN(
1062 "Accessibility.CrosAlwaysShowA11yMenu",
James Cookc63b9fd2017-08-18 18:48:321063 prefs->GetBoolean(ash::prefs::kShouldAlwaysShowAccessibilityMenu));
[email protected]0b5a0d2b2013-10-30 03:43:401064
[email protected]ced247a2014-06-13 19:14:191065 bool autoclick_enabled =
James Cookc63b9fd2017-08-18 18:48:321066 prefs->GetBoolean(ash::prefs::kAccessibilityAutoclickEnabled);
[email protected]0b5a0d2b2013-10-30 03:43:401067 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosAutoclick", autoclick_enabled);
1068 if (autoclick_enabled) {
1069 // We only want to log the autoclick delay if the user has actually
1070 // enabled autoclick.
1071 UMA_HISTOGRAM_CUSTOM_TIMES(
1072 "Accessibility.CrosAutoclickDelay",
1073 base::TimeDelta::FromMilliseconds(
James Cookc63b9fd2017-08-18 18:48:321074 prefs->GetInteger(ash::prefs::kAccessibilityAutoclickDelayMs)),
[email protected]0b5a0d2b2013-10-30 03:43:401075 base::TimeDelta::FromMilliseconds(1),
James Cookc63b9fd2017-08-18 18:48:321076 base::TimeDelta::FromMilliseconds(3000), 50);
[email protected]0b5a0d2b2013-10-30 03:43:401077 }
[email protected]ca3a0a82013-06-18 06:52:121078 }
dmazzoni756089a22016-03-15 23:55:161079 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCaretHighlight",
1080 IsCaretHighlightEnabled());
1081 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCursorHighlight",
1082 IsCursorHighlightEnabled());
1083 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosFocusHighlight",
1084 IsFocusHighlightEnabled());
1085 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSelectToSpeak",
1086 IsSelectToSpeakEnabled());
1087 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSwitchAccess",
1088 IsSwitchAccessEnabled());
[email protected]1dfebfc2013-06-04 03:14:321089}
1090
1091void AccessibilityManager::Observe(
1092 int type,
1093 const content::NotificationSource& source,
1094 const content::NotificationDetails& details) {
1095 switch (type) {
[email protected]093d9ba2013-07-23 19:26:211096 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
[email protected]9cf54f362013-07-01 07:28:121097 // Update |profile_| when entering the login screen.
[email protected]c20122572013-12-16 20:35:581098 Profile* profile = ProfileManager::GetActiveUserProfile();
[email protected]d888cdc2013-06-24 17:06:201099 if (ProfileHelper::IsSigninProfile(profile))
1100 SetProfile(profile);
[email protected]1dfebfc2013-06-04 03:14:321101 break;
[email protected]d888cdc2013-06-24 17:06:201102 }
Yuki Awanod59b6492017-07-28 00:52:111103 case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED:
1104 // Update |profile_| when login user profile is prepared.
1105 // NOTIFICATION_SESSION_STARTED is not fired from UserSessionManager, but
1106 // profile may be changed by UserSessionManager in OOBE flow.
1107 SetProfile(ProfileManager::GetActiveUserProfile());
1108 break;
[email protected]e6f20642013-06-11 17:05:461109 case chrome::NOTIFICATION_SESSION_STARTED:
1110 // Update |profile_| when entering a session.
[email protected]c20122572013-12-16 20:35:581111 SetProfile(ProfileManager::GetActiveUserProfile());
[email protected]0e9504d2013-11-05 02:33:291112
[email protected]c20122572013-12-16 20:35:581113 // Add a session state observer to be able to monitor session changes.
xiyuan5d8d3ba2017-03-01 21:34:401114 if (!session_state_observer_.get())
[email protected]c20122572013-12-16 20:35:581115 session_state_observer_.reset(
xiyuan5d8d3ba2017-03-01 21:34:401116 new user_manager::ScopedUserSessionStateObserver(this));
[email protected]1dfebfc2013-06-04 03:14:321117 break;
[email protected]1dfebfc2013-06-04 03:14:321118 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
[email protected]e6f20642013-06-11 17:05:461119 // Update |profile_| when exiting a session or shutting down.
1120 Profile* profile = content::Source<Profile>(source).ptr();
1121 if (profile_ == profile)
1122 SetProfile(NULL);
[email protected]1dfebfc2013-06-04 03:14:321123 break;
1124 }
David Tseng768d7982017-12-21 00:20:111125 case chrome::NOTIFICATION_APP_TERMINATING: {
James Cook0c4f37ac02018-01-17 02:17:091126 app_terminating_ = true;
David Tseng768d7982017-12-21 00:20:111127 break;
1128 }
Qiang Xu95eea572018-02-17 08:10:311129 case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE: {
Qiang Xu0f122282018-04-19 16:55:401130 // Avoid unnecessary mojo IPC to ash when focus highlight feature is not
1131 // enabled.
1132 if (!IsFocusHighlightEnabled())
1133 return;
Qiang Xu95eea572018-02-17 08:10:311134 content::FocusedNodeDetails* node_details =
1135 content::Details<content::FocusedNodeDetails>(details).ptr();
1136 accessibility_controller_->SetFocusHighlightRect(
1137 node_details->node_bounds_in_screen);
1138 break;
1139 }
[email protected]1dfebfc2013-06-04 03:14:321140 }
1141}
1142
[email protected]2e5e0b12014-05-07 13:30:201143void AccessibilityManager::OnBrailleDisplayStateChanged(
[email protected]8c79e3f2013-10-30 01:05:141144 const DisplayState& display_state) {
[email protected]a81b2c32014-03-28 06:35:011145 braille_display_connected_ = display_state.available;
Qiang Xu797a8e72018-01-21 11:19:081146 accessibility_controller_->BrailleDisplayStateChanged(
1147 braille_display_connected_);
[email protected]2e5e0b12014-05-07 13:30:201148 UpdateBrailleImeState();
[email protected]8c79e3f2013-10-30 01:05:141149}
[email protected]0e9504d2013-11-05 02:33:291150
[email protected]2e5e0b12014-05-07 13:30:201151void AccessibilityManager::OnBrailleKeyEvent(const KeyEvent& event) {
1152 // Ensure the braille IME is active on braille keyboard (dots) input.
1153 if ((event.command ==
1154 extensions::api::braille_display_private::KEY_COMMAND_DOTS) &&
1155 !braille_ime_current_) {
[email protected]f0881cf2014-08-15 23:31:421156 input_method::InputMethodManager::Get()
1157 ->GetActiveIMEState()
jamescook2d60f032017-06-01 00:55:211158 ->ChangeInputMethod(extension_ime_util::kBrailleImeEngineId,
[email protected]f0881cf2014-08-15 23:31:421159 false /* show_message */);
[email protected]2e5e0b12014-05-07 13:30:201160 }
1161}
1162
dtsengfb6d7cd2016-01-20 23:00:131163void AccessibilityManager::OnExtensionUnloaded(
1164 content::BrowserContext* browser_context,
1165 const extensions::Extension* extension,
limasdf0deef2042017-05-03 19:17:171166 extensions::UnloadedExtensionReason reason) {
dtsengfb6d7cd2016-01-20 23:00:131167 if (extension->id() == keyboard_listener_extension_id_) {
1168 keyboard_listener_extension_id_ = std::string();
1169 keyboard_listener_capture_ = false;
dtsengfb6d7cd2016-01-20 23:00:131170 }
1171}
1172
1173void AccessibilityManager::OnShutdown(extensions::ExtensionRegistry* registry) {
1174 extension_registry_observer_.Remove(registry);
1175}
1176
dmazzoni337c5af2016-09-13 23:08:571177void AccessibilityManager::PostLoadChromeVox() {
James Cook0c4f37ac02018-01-17 02:17:091178 // In browser_tests loading the ChromeVox extension can race with shutdown.
1179 // http://crbug.com/801700
1180 if (app_terminating_)
1181 return;
1182
[email protected]ee8bbd972014-02-03 06:52:471183 // Do any setup work needed immediately after ChromeVox actually loads.
sadrulcdc2bb42016-07-13 19:44:511184 PlayEarcon(SOUND_SPOKEN_FEEDBACK_ENABLED, PlaySoundOption::ALWAYS);
[email protected]0e9504d2013-11-05 02:33:291185
dtseng4702f8e2017-01-11 18:54:121186 extensions::EventRouter* event_router =
1187 extensions::EventRouter::Get(profile_);
dtseng703a2042015-01-22 17:46:511188
Katie D30e08412018-05-02 17:24:221189 std::unique_ptr<base::ListValue> event_args =
1190 std::make_unique<base::ListValue>();
dtseng4702f8e2017-01-11 18:54:121191 std::unique_ptr<extensions::Event> event(new extensions::Event(
1192 extensions::events::ACCESSIBILITY_PRIVATE_ON_INTRODUCE_CHROME_VOX,
1193 extensions::api::accessibility_private::OnIntroduceChromeVox::kEventName,
1194 std::move(event_args)));
1195 event_router->DispatchEventWithLazyListener(
1196 extension_misc::kChromeVoxExtensionId, std::move(event));
dmazzoni94a4f882015-11-13 05:46:521197
James Cook769799b2018-03-12 16:59:041198 if (!chromevox_panel_) {
tbarziccd5ad222017-03-24 04:46:311199 chromevox_panel_ = new ChromeVoxPanel(
1200 profile_,
1201 session_manager::SessionManager::Get()->IsUserSessionBlocked());
dmazzoni94a4f882015-11-13 05:46:521202 chromevox_panel_widget_observer_.reset(
1203 new ChromeVoxPanelWidgetObserver(chromevox_panel_->GetWidget(), this));
1204 }
dtsengd50debe32016-12-29 06:23:371205
1206 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
Dominic Mazzonic85a5c92017-08-31 18:53:301207 ::switches::kEnableAudioFocus)) {
dtsengd50debe32016-12-29 06:23:371208 base::CommandLine::ForCurrentProcess()->AppendSwitch(
Dominic Mazzonic85a5c92017-08-31 18:53:301209 ::switches::kEnableAudioFocus);
dtsengd50debe32016-12-29 06:23:371210 }
[email protected]0e9504d2013-11-05 02:33:291211}
1212
dmazzoni337c5af2016-09-13 23:08:571213void AccessibilityManager::PostUnloadChromeVox() {
[email protected]9d6c91362013-12-07 21:56:271214 // Do any teardown work needed immediately after ChromeVox actually unloads.
sadrulcdc2bb42016-07-13 19:44:511215 PlayEarcon(SOUND_SPOKEN_FEEDBACK_DISABLED, PlaySoundOption::ALWAYS);
Qiang Xu89af823e2017-12-05 04:04:471216
dmazzonifb33d592014-10-30 19:26:541217 // Clear the accessibility focus ring.
Qiang Xu56a75812018-03-15 00:28:341218 SetFocusRing(std::vector<gfx::Rect>(),
1219 ash::mojom::FocusRingBehavior::PERSIST_FOCUS_RING);
dmazzoni337c5af2016-09-13 23:08:571220
1221 if (chromevox_panel_) {
1222 chromevox_panel_->Close();
1223 chromevox_panel_ = nullptr;
1224 }
dtseng3a17f212017-03-25 08:58:521225
1226 // In case the user darkened the screen, undarken it now.
Qiang Xu4e5853d382018-01-09 07:21:071227 SetDarkenScreen(false);
Katie D6264a8e2018-02-07 02:32:201228
1229 // Stop speech.
1230 TtsController::GetInstance()->Stop();
[email protected]9d6c91362013-12-07 21:56:271231}
1232
dmazzoni63199b12016-10-19 15:44:361233void AccessibilityManager::PostSwitchChromeVoxProfile() {
tbarziccd5ad222017-03-24 04:46:311234 ReloadChromeVoxPanel();
1235}
1236
1237void AccessibilityManager::ReloadChromeVoxPanel() {
dmazzoni63199b12016-10-19 15:44:361238 if (chromevox_panel_) {
James Cook769799b2018-03-12 16:59:041239 chromevox_panel_->CloseNow();
dmazzoni63199b12016-10-19 15:44:361240 chromevox_panel_ = nullptr;
1241 }
tbarziccd5ad222017-03-24 04:46:311242 chromevox_panel_ = new ChromeVoxPanel(
1243 profile_, session_manager::SessionManager::Get()->IsUserSessionBlocked());
dmazzoni63199b12016-10-19 15:44:361244 chromevox_panel_widget_observer_.reset(
1245 new ChromeVoxPanelWidgetObserver(chromevox_panel_->GetWidget(), this));
1246}
1247
dmazzoni94a4f882015-11-13 05:46:521248void AccessibilityManager::OnChromeVoxPanelClosing() {
jamescook788b4fc2017-05-18 16:16:061249 chromevox_panel_widget_observer_.reset();
dmazzoni94a4f882015-11-13 05:46:521250 chromevox_panel_ = nullptr;
dmazzoni94a4f882015-11-13 05:46:521251}
1252
1253void AccessibilityManager::OnChromeVoxPanelDestroying() {
1254 chromevox_panel_widget_observer_.reset(nullptr);
1255 chromevox_panel_ = nullptr;
1256}
1257
Katie D6264a8e2018-02-07 02:32:201258void AccessibilityManager::PostUnloadSelectToSpeak() {
1259 // Do any teardown work needed immediately after Select-to-Speak actually
1260 // unloads.
1261
1262 // Clear the accessibility focus ring and highlight.
Qiang Xu56a75812018-03-15 00:28:341263 HideFocusRing();
1264 HideHighlights();
Katie D6264a8e2018-02-07 02:32:201265
1266 // Stop speech.
1267 TtsController::GetInstance()->Stop();
1268}
1269
dtsengfb6d7cd2016-01-20 23:00:131270void AccessibilityManager::SetKeyboardListenerExtensionId(
1271 const std::string& id,
1272 content::BrowserContext* context) {
1273 keyboard_listener_extension_id_ = id;
1274
1275 extensions::ExtensionRegistry* registry =
1276 extensions::ExtensionRegistry::Get(context);
1277 if (!extension_registry_observer_.IsObserving(registry) && !id.empty())
1278 extension_registry_observer_.Add(registry);
1279}
1280
elichtenberga108c8a2017-06-02 21:13:191281void AccessibilityManager::SetSwitchAccessKeys(const std::set<int>& key_codes) {
1282 if (switch_access_enabled_)
1283 switch_access_event_handler_->SetKeysToCapture(key_codes);
1284}
1285
Zach Helfinsteinbbb6bad2018-05-02 18:21:511286bool AccessibilityManager::ToggleDictation() {
David Tseng8a5de492018-01-17 20:41:371287 if (!profile_)
Zach Helfinsteinbbb6bad2018-05-02 18:21:511288 return false;
David Tseng8a5de492018-01-17 20:41:371289
1290 if (!dictation_.get())
1291 dictation_ = std::make_unique<DictationChromeos>(profile_);
1292
Zach Helfinsteinbbb6bad2018-05-02 18:21:511293 return dictation_->OnToggleDictation();
David Tseng8a5de492018-01-17 20:41:371294}
1295
Qiang Xu56a75812018-03-15 00:28:341296void AccessibilityManager::SetFocusRingColor(SkColor color) {
1297 accessibility_focus_ring_controller_->SetFocusRingColor(color);
1298}
1299
1300void AccessibilityManager::ResetFocusRingColor() {
1301 accessibility_focus_ring_controller_->ResetFocusRingColor();
1302}
1303
1304void AccessibilityManager::SetFocusRing(
1305 const std::vector<gfx::Rect>& rects_in_screen,
1306 ash::mojom::FocusRingBehavior focus_ring_behavior) {
1307 accessibility_focus_ring_controller_->SetFocusRing(rects_in_screen,
1308 focus_ring_behavior);
1309 if (focus_ring_observer_for_test_)
1310 focus_ring_observer_for_test_.Run();
1311}
1312
1313void AccessibilityManager::HideFocusRing() {
1314 accessibility_focus_ring_controller_->HideFocusRing();
1315 if (focus_ring_observer_for_test_)
1316 focus_ring_observer_for_test_.Run();
1317}
1318
1319void AccessibilityManager::SetHighlights(
1320 const std::vector<gfx::Rect>& rects_in_screen,
1321 SkColor color) {
1322 accessibility_focus_ring_controller_->SetHighlights(rects_in_screen, color);
1323}
1324
1325void AccessibilityManager::HideHighlights() {
1326 accessibility_focus_ring_controller_->HideHighlights();
1327}
1328
Qiang Xu797a8e72018-01-21 11:19:081329void AccessibilityManager::SetProfileForTest(Profile* profile) {
1330 SetProfile(profile);
1331}
1332
1333// static
1334void AccessibilityManager::SetBrailleControllerForTest(
1335 BrailleController* controller) {
1336 g_braille_controller_for_test = controller;
1337}
1338
1339void AccessibilityManager::FlushForTesting() {
1340 accessibility_controller_.FlushForTesting();
1341}
1342
Qiang Xu56a75812018-03-15 00:28:341343void AccessibilityManager::SetFocusRingObserverForTest(
1344 base::RepeatingCallback<void()> observer) {
1345 focus_ring_observer_for_test_ = observer;
1346}
1347
[email protected]1dfebfc2013-06-04 03:14:321348} // namespace chromeos