blob: fc1eea799e41ca6bb225ab0b32c760a3a77f708c [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>
avi8a07d53892015-12-24 22:13:5312
pkotwicz04d5c892015-01-15 00:05:3613#include "ash/audio/sounds.h"
14#include "ash/autoclick/autoclick_controller.h"
15#include "ash/high_contrast/high_contrast_controller.h"
16#include "ash/metrics/user_metrics_recorder.h"
dmazzoniff86e3472016-06-03 19:52:3217#include "ash/root_window_controller.h"
pkotwicz04d5c892015-01-15 00:05:3618#include "ash/session/session_state_delegate.h"
mswa7e8a5f2016-03-01 04:15:0619#include "ash/shelf/shelf.h"
dmazzoni94a4f882015-11-13 05:46:5220#include "ash/shelf/shelf_layout_manager.h"
pkotwicz04d5c892015-01-15 00:05:3621#include "ash/shell.h"
22#include "ash/sticky_keys/sticky_keys_controller.h"
23#include "ash/system/tray/system_tray_notifier.h"
[email protected]44beb032014-06-11 06:24:3724#include "base/callback.h"
25#include "base/callback_helpers.h"
plundbladcf1d08f2015-09-28 09:18:5826#include "base/command_line.h"
avi8a07d53892015-12-24 22:13:5327#include "base/macros.h"
[email protected]1dfebfc2013-06-04 03:14:3228#include "base/memory/singleton.h"
29#include "base/metrics/histogram.h"
[email protected]ab38d192013-12-13 11:38:5830#include "base/path_service.h"
[email protected]2e5e0b12014-05-07 13:30:2031#include "base/strings/string_split.h"
32#include "base/strings/string_util.h"
[email protected]0b5a0d2b2013-10-30 03:43:4033#include "base/time/time.h"
[email protected]0aae2fe2013-07-05 07:04:4234#include "base/values.h"
[email protected]1dfebfc2013-06-04 03:14:3235#include "chrome/browser/accessibility/accessibility_extension_api.h"
36#include "chrome/browser/browser_process.h"
[email protected]fdf40f3e2013-07-11 23:55:4637#include "chrome/browser/chrome_notification_types.h"
dmazzonib93107c2016-03-22 21:51:1838#include "chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h"
pkotwicz04d5c892015-01-15 00:05:3639#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
[email protected]83d82d42014-05-16 02:04:4240#include "chrome/browser/chromeos/login/lock/screen_locker.h"
41#include "chrome/browser/chromeos/login/ui/login_display_host.h"
[email protected]83d82d42014-05-16 02:04:4242#include "chrome/browser/chromeos/login/ui/webui_login_view.h"
[email protected]e6f20642013-06-11 17:05:4643#include "chrome/browser/chromeos/profiles/profile_helper.h"
dmazzonifb33d592014-10-30 19:26:5444#include "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h"
plundbladcf1d08f2015-09-28 09:18:5845#include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
[email protected]1dfebfc2013-06-04 03:14:3246#include "chrome/browser/extensions/component_loader.h"
47#include "chrome/browser/extensions/extension_service.h"
rdevlin.cronin4bb32d72015-06-02 21:55:0148#include "chrome/browser/extensions/tab_helper.h"
gogeralddde4ee02015-08-26 18:58:4949#include "chrome/browser/prefs/incognito_mode_prefs.h"
[email protected]1dfebfc2013-06-04 03:14:3250#include "chrome/browser/profiles/profile.h"
51#include "chrome/browser/profiles/profile_manager.h"
[email protected]ab38d192013-12-13 11:38:5852#include "chrome/common/chrome_paths.h"
[email protected]9848bf6c2014-05-09 12:34:0053#include "chrome/common/extensions/api/accessibility_private.h"
[email protected]dccba4f82014-05-29 00:52:5654#include "chrome/common/extensions/extension_constants.h"
[email protected]1dfebfc2013-06-04 03:14:3255#include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
56#include "chrome/common/pref_names.h"
[email protected]b58d2f82014-08-09 05:36:1457#include "chrome/grit/browser_resources.h"
warx533c8f62016-04-12 01:19:4358#include "chromeos/audio/audio_a11y_controller.h"
[email protected]ce89d9392013-12-11 21:05:2059#include "chromeos/audio/chromeos_sounds.h"
[email protected]0aae2fe2013-07-05 07:04:4260#include "chromeos/login/login_state.h"
brettwb1fc1b82016-02-02 00:19:0861#include "components/prefs/pref_member.h"
62#include "components/prefs/pref_service.h"
[email protected]4d390782014-08-15 09:22:5863#include "components/user_manager/user_manager.h"
[email protected]1dfebfc2013-06-04 03:14:3264#include "content/public/browser/browser_accessibility_state.h"
[email protected]8c79e3f2013-10-30 01:05:1465#include "content/public/browser/browser_thread.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/render_process_host.h"
70#include "content/public/browser/render_view_host.h"
71#include "content/public/browser/web_contents.h"
72#include "content/public/browser/web_ui.h"
plundbladcf1d08f2015-09-28 09:18:5873#include "content/public/common/content_switches.h"
juncaicf523332015-06-04 00:14:0474#include "extensions/browser/event_router.h"
rob52277c82016-02-07 17:28:5775#include "extensions/browser/extension_api_frame_id_map.h"
reillyga3acbc12014-11-11 23:17:1276#include "extensions/browser/extension_registry.h"
[email protected]59b0e602014-01-30 00:41:2477#include "extensions/browser/extension_system.h"
[email protected]1dfebfc2013-06-04 03:14:3278#include "extensions/browser/file_reader.h"
rdevlin.cronin4bb32d72015-06-02 21:55:0179#include "extensions/browser/script_executor.h"
[email protected]e4452d32013-11-15 23:07:4180#include "extensions/common/extension.h"
[email protected]fb820c02014-03-13 15:07:0881#include "extensions/common/extension_messages.h"
[email protected]1dfebfc2013-06-04 03:14:3282#include "extensions/common/extension_resource.h"
hanxi79f7a572015-03-09 20:46:5983#include "extensions/common/host_id.h"
[email protected]12b0a842013-12-04 20:48:1384#include "media/audio/sounds/sounds_manager.h"
shuchen179b1f42014-11-27 17:24:4085#include "ui/base/ime/chromeos/input_method_manager.h"
[email protected]1dfebfc2013-06-04 03:14:3286#include "ui/base/resource/resource_bundle.h"
[email protected]e1b299b2014-01-29 23:53:4187#include "ui/keyboard/keyboard_controller.h"
88#include "ui/keyboard/keyboard_util.h"
[email protected]1dfebfc2013-06-04 03:14:3289
[email protected]8c79e3f2013-10-30 01:05:1490using content::BrowserThread;
[email protected]1dfebfc2013-06-04 03:14:3291using content::RenderViewHost;
[email protected]8c79e3f2013-10-30 01:05:1492using extensions::api::braille_display_private::BrailleController;
93using extensions::api::braille_display_private::DisplayState;
[email protected]2e5e0b12014-05-07 13:30:2094using extensions::api::braille_display_private::KeyEvent;
plundbladcf1d08f2015-09-28 09:18:5895using extensions::api::braille_display_private::StubBrailleController;
[email protected]1dfebfc2013-06-04 03:14:3296
97namespace chromeos {
98
99namespace {
100
101static chromeos::AccessibilityManager* g_accessibility_manager = NULL;
102
[email protected]8c79e3f2013-10-30 01:05:14103static BrailleController* g_braille_controller_for_test = NULL;
104
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();
111 if (command_line->HasSwitch(switches::kTestType))
112 return StubBrailleController::GetInstance();
113 return BrailleController::GetInstance();
[email protected]8c79e3f2013-10-30 01:05:14114}
115
[email protected]ab38d192013-12-13 11:38:58116base::FilePath GetChromeVoxPath() {
117 base::FilePath path;
118 if (!PathService::Get(chrome::DIR_RESOURCES, &path))
119 NOTREACHED();
120 path = path.Append(extension_misc::kChromeVoxExtensionPath);
121 return path;
122}
123
rdevlin.cronin4bb32d72015-06-02 21:55:01124// Uses the ScriptExecutor associated with the given |render_view_host| to
125// execute the given |code|.
126void ExecuteScriptHelper(
127 content::RenderViewHost* render_view_host,
128 const std::string& code,
129 const std::string& extension_id) {
130 content::WebContents* web_contents =
131 content::WebContents::FromRenderViewHost(render_view_host);
132 if (!web_contents)
133 return;
dtsengd35baea62015-06-09 22:11:04134 if (!extensions::TabHelper::FromWebContents(web_contents))
135 extensions::TabHelper::CreateForWebContents(web_contents);
rob52277c82016-02-07 17:28:57136 extensions::TabHelper::FromWebContents(web_contents)
137 ->script_executor()
138 ->ExecuteScript(HostID(HostID::EXTENSIONS, extension_id),
139 extensions::ScriptExecutor::JAVASCRIPT, code,
140 extensions::ScriptExecutor::INCLUDE_SUB_FRAMES,
141 extensions::ExtensionApiFrameIdMap::kTopFrameId,
142 extensions::ScriptExecutor::DONT_MATCH_ABOUT_BLANK,
143 extensions::UserScript::DOCUMENT_IDLE,
144 extensions::ScriptExecutor::ISOLATED_WORLD,
145 extensions::ScriptExecutor::DEFAULT_PROCESS,
146 GURL(), // No webview src.
147 GURL(), // No file url.
148 false, // Not user gesture.
149 extensions::ScriptExecutor::NO_RESULT,
150 extensions::ScriptExecutor::ExecuteScriptCallback());
rdevlin.cronin4bb32d72015-06-02 21:55:01151}
152
[email protected]1dfebfc2013-06-04 03:14:32153// Helper class that directly loads an extension's content scripts into
154// all of the frames corresponding to a given RenderViewHost.
155class ContentScriptLoader {
156 public:
157 // Initialize the ContentScriptLoader with the ID of the extension
158 // and the RenderViewHost where the scripts should be loaded.
159 ContentScriptLoader(const std::string& extension_id,
160 int render_process_id,
161 int render_view_id)
162 : extension_id_(extension_id),
163 render_process_id_(render_process_id),
164 render_view_id_(render_view_id) {}
165
166 // Call this once with the ExtensionResource corresponding to each
167 // content script to be loaded.
168 void AppendScript(extensions::ExtensionResource resource) {
169 resources_.push(resource);
170 }
171
[email protected]5ecf6122013-10-31 12:24:09172 // Finally, call this method once to fetch all of the resources and
[email protected]1dfebfc2013-06-04 03:14:32173 // load them. This method will delete this object when done.
174 void Run() {
175 if (resources_.empty()) {
176 delete this;
177 return;
178 }
179
180 extensions::ExtensionResource resource = resources_.front();
181 resources_.pop();
182 scoped_refptr<FileReader> reader(new FileReader(resource, base::Bind(
183 &ContentScriptLoader::OnFileLoaded, base::Unretained(this))));
184 reader->Start();
185 }
186
187 private:
188 void OnFileLoaded(bool success, const std::string& data) {
189 if (success) {
[email protected]1dfebfc2013-06-04 03:14:32190 RenderViewHost* render_view_host =
191 RenderViewHost::FromID(render_process_id_, render_view_id_);
rdevlin.cronin4bb32d72015-06-02 21:55:01192 if (render_view_host)
193 ExecuteScriptHelper(render_view_host, data, extension_id_);
[email protected]1dfebfc2013-06-04 03:14:32194 }
195 Run();
196 }
197
198 std::string extension_id_;
199 int render_process_id_;
200 int render_view_id_;
201 std::queue<extensions::ExtensionResource> resources_;
202};
203
[email protected]44beb032014-06-11 06:24:37204void InjectChromeVoxContentScript(
205 ExtensionService* extension_service,
206 int render_process_id,
207 int render_view_id,
208 const base::Closure& done_cb);
209
210void LoadChromeVoxExtension(
211 Profile* profile,
212 RenderViewHost* render_view_host,
213 base::Closure done_cb) {
[email protected]b0a2ce32013-07-23 15:24:53214 ExtensionService* extension_service =
215 extensions::ExtensionSystem::Get(profile)->extension_service();
[email protected]f8aa76842014-02-05 19:11:06216 if (render_view_host) {
[email protected]44beb032014-06-11 06:24:37217 // Wrap the passed in callback to inject the content script.
218 done_cb = base::Bind(
219 &InjectChromeVoxContentScript,
220 extension_service,
221 render_view_host->GetProcess()->GetID(),
222 render_view_host->GetRoutingID(),
223 done_cb);
[email protected]b0a2ce32013-07-23 15:24:53224 }
[email protected]44beb032014-06-11 06:24:37225 extension_service->component_loader()->AddChromeVoxExtension(done_cb);
226}
227
228void InjectChromeVoxContentScript(
229 ExtensionService* extension_service,
230 int render_process_id,
231 int render_view_id,
232 const base::Closure& done_cb) {
233 // Make sure to always run |done_cb|. ChromeVox was loaded even if we end up
234 // not injecting into this particular render view.
235 base::ScopedClosureRunner done_runner(done_cb);
236 RenderViewHost* render_view_host =
237 RenderViewHost::FromID(render_process_id, render_view_id);
238 if (!render_view_host)
239 return;
plundblad1384a23d2015-11-02 14:37:30240 const content::WebContents* web_contents =
241 content::WebContents::FromRenderViewHost(render_view_host);
242 GURL content_url;
243 if (web_contents)
244 content_url = web_contents->GetLastCommittedURL();
[email protected]44beb032014-06-11 06:24:37245 const extensions::Extension* extension =
reillyga3acbc12014-11-11 23:17:12246 extensions::ExtensionRegistry::Get(extension_service->profile())
247 ->enabled_extensions()
248 .GetByID(extension_misc::kChromeVoxExtensionId);
[email protected]44beb032014-06-11 06:24:37249
250 // Set a flag to tell ChromeVox that it's just been enabled,
251 // so that it won't interrupt our speech feedback enabled message.
rdevlin.cronin4bb32d72015-06-02 21:55:01252 ExecuteScriptHelper(render_view_host, "window.INJECTED_AFTER_LOAD = true;",
253 extension->id());
[email protected]44beb032014-06-11 06:24:37254
255 // Inject ChromeVox' content scripts.
256 ContentScriptLoader* loader = new ContentScriptLoader(
257 extension->id(), render_view_host->GetProcess()->GetID(),
258 render_view_host->GetRoutingID());
259
260 const extensions::UserScriptList& content_scripts =
261 extensions::ContentScriptsInfo::GetContentScripts(extension);
262 for (size_t i = 0; i < content_scripts.size(); i++) {
263 const extensions::UserScript& script = content_scripts[i];
plundblad1384a23d2015-11-02 14:37:30264 if (web_contents && !script.MatchesURL(content_url))
265 continue;
[email protected]44beb032014-06-11 06:24:37266 for (size_t j = 0; j < script.js_scripts().size(); ++j) {
[email protected]07f3ea92014-08-14 05:23:38267 const extensions::UserScript::File& file = script.js_scripts()[j];
[email protected]44beb032014-06-11 06:24:37268 extensions::ExtensionResource resource = extension->GetResource(
269 file.relative_path());
270 loader->AppendScript(resource);
271 }
272 }
273 loader->Run(); // It cleans itself up when done.
[email protected]b0a2ce32013-07-23 15:24:53274}
275
276void UnloadChromeVoxExtension(Profile* profile) {
[email protected]ab38d192013-12-13 11:38:58277 base::FilePath path = GetChromeVoxPath();
[email protected]b0a2ce32013-07-23 15:24:53278 ExtensionService* extension_service =
279 extensions::ExtensionSystem::Get(profile)->extension_service();
[email protected]b0a2ce32013-07-23 15:24:53280 extension_service->component_loader()->Remove(path);
[email protected]b0a2ce32013-07-23 15:24:53281}
282
[email protected]1dfebfc2013-06-04 03:14:32283} // namespace
284
dmazzoni94a4f882015-11-13 05:46:52285class ChromeVoxPanelWidgetObserver : public views::WidgetObserver {
286 public:
287 ChromeVoxPanelWidgetObserver(views::Widget* widget,
288 AccessibilityManager* manager)
289 : widget_(widget), manager_(manager) {
290 widget_->AddObserver(this);
291 }
292
293 void OnWidgetClosing(views::Widget* widget) override {
294 CHECK_EQ(widget_, widget);
295 widget->RemoveObserver(this);
296 manager_->OnChromeVoxPanelClosing();
297 }
298
299 void OnWidgetDestroying(views::Widget* widget) override {
300 CHECK_EQ(widget_, widget);
301 widget->RemoveObserver(this);
302 manager_->OnChromeVoxPanelDestroying();
303 }
304
305 private:
306 views::Widget* widget_;
307 AccessibilityManager* manager_;
308
309 DISALLOW_COPY_AND_ASSIGN(ChromeVoxPanelWidgetObserver);
310};
311
[email protected]1dfebfc2013-06-04 03:14:32312///////////////////////////////////////////////////////////////////////////////
313// AccessibilityStatusEventDetails
314
315AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
[email protected]d8edc9c2014-02-25 00:06:03316 AccessibilityNotificationType notification_type,
[email protected]1dfebfc2013-06-04 03:14:32317 bool enabled,
pkotwicz0991c822014-10-31 04:21:03318 ui::AccessibilityNotificationVisibility notify)
[email protected]d8edc9c2014-02-25 00:06:03319 : notification_type(notification_type),
320 enabled(enabled),
pkotwicz0991c822014-10-31 04:21:03321 magnifier_type(ui::kDefaultMagnifierType),
[email protected]1dfebfc2013-06-04 03:14:32322 notify(notify) {}
323
324AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
[email protected]d8edc9c2014-02-25 00:06:03325 AccessibilityNotificationType notification_type,
[email protected]1dfebfc2013-06-04 03:14:32326 bool enabled,
pkotwicz0991c822014-10-31 04:21:03327 ui::MagnifierType magnifier_type,
328 ui::AccessibilityNotificationVisibility notify)
[email protected]d8edc9c2014-02-25 00:06:03329 : notification_type(notification_type),
330 enabled(enabled),
[email protected]1dfebfc2013-06-04 03:14:32331 magnifier_type(magnifier_type),
332 notify(notify) {}
333
334///////////////////////////////////////////////////////////////////////////////
335//
[email protected]0aae2fe2013-07-05 07:04:42336// AccessibilityManager::PrefHandler
337
338AccessibilityManager::PrefHandler::PrefHandler(const char* pref_path)
339 : pref_path_(pref_path) {}
340
341AccessibilityManager::PrefHandler::~PrefHandler() {}
342
343void AccessibilityManager::PrefHandler::HandleProfileChanged(
344 Profile* previous_profile, Profile* current_profile) {
345 // Returns if the current profile is null.
346 if (!current_profile)
347 return;
348
349 // If the user set a pref value on the login screen and is now starting a
350 // session with a new profile, copy the pref value to the profile.
351 if ((previous_profile &&
352 ProfileHelper::IsSigninProfile(previous_profile) &&
353 current_profile->IsNewProfile() &&
354 !ProfileHelper::IsSigninProfile(current_profile)) ||
355 // Special case for Guest mode:
356 // Guest mode launches a guest-mode browser process before session starts,
357 // so the previous profile is null.
358 (!previous_profile &&
359 current_profile->IsGuestSession())) {
360 // Returns if the pref has not been set by the user.
361 const PrefService::Preference* pref = ProfileHelper::GetSigninProfile()->
362 GetPrefs()->FindPreference(pref_path_);
363 if (!pref || !pref->IsUserControlled())
364 return;
365
366 // Copy the pref value from the signin screen.
367 const base::Value* value_on_login = pref->GetValue();
368 PrefService* user_prefs = current_profile->GetPrefs();
369 user_prefs->Set(pref_path_, *value_on_login);
370 }
371}
372
373///////////////////////////////////////////////////////////////////////////////
374//
[email protected]1dfebfc2013-06-04 03:14:32375// AccessibilityManager
376
377// static
378void AccessibilityManager::Initialize() {
379 CHECK(g_accessibility_manager == NULL);
380 g_accessibility_manager = new AccessibilityManager();
381}
382
383// static
384void AccessibilityManager::Shutdown() {
385 CHECK(g_accessibility_manager);
386 delete g_accessibility_manager;
387 g_accessibility_manager = NULL;
388}
389
390// static
391AccessibilityManager* AccessibilityManager::Get() {
392 return g_accessibility_manager;
393}
394
[email protected]d80f19302013-06-07 13:12:14395AccessibilityManager::AccessibilityManager()
396 : profile_(NULL),
[email protected]b0a2ce32013-07-23 15:24:53397 chrome_vox_loaded_on_lock_screen_(false),
398 chrome_vox_loaded_on_user_screen_(false),
[email protected]ced247a2014-06-13 19:14:19399 large_cursor_pref_handler_(prefs::kAccessibilityLargeCursorEnabled),
400 spoken_feedback_pref_handler_(prefs::kAccessibilitySpokenFeedbackEnabled),
401 high_contrast_pref_handler_(prefs::kAccessibilityHighContrastEnabled),
402 autoclick_pref_handler_(prefs::kAccessibilityAutoclickEnabled),
403 autoclick_delay_pref_handler_(prefs::kAccessibilityAutoclickDelayMs),
404 virtual_keyboard_pref_handler_(
405 prefs::kAccessibilityVirtualKeyboardEnabled),
warx533c8f62016-04-12 01:19:43406 mono_audio_pref_handler_(
407 prefs::kAccessibilityMonoAudioEnabled),
dmazzoni756089a22016-03-15 23:55:16408 caret_highlight_pref_handler_(prefs::kAccessibilityCaretHighlightEnabled),
409 cursor_highlight_pref_handler_(
410 prefs::kAccessibilityCursorHighlightEnabled),
411 focus_highlight_pref_handler_(prefs::kAccessibilityFocusHighlightEnabled),
412 select_to_speak_pref_handler_(prefs::kAccessibilitySelectToSpeakEnabled),
413 switch_access_pref_handler_(prefs::kAccessibilitySwitchAccessEnabled),
[email protected]d80f19302013-06-07 13:12:14414 large_cursor_enabled_(false),
[email protected]93a534e2013-06-20 16:41:44415 sticky_keys_enabled_(false),
[email protected]d80f19302013-06-07 13:12:14416 spoken_feedback_enabled_(false),
417 high_contrast_enabled_(false),
[email protected]186ba06bc2013-11-26 18:02:19418 autoclick_enabled_(false),
[email protected]84d652d2013-10-23 13:57:57419 autoclick_delay_ms_(ash::AutoclickController::kDefaultAutoclickDelayMs),
[email protected]e1b299b2014-01-29 23:53:41420 virtual_keyboard_enabled_(false),
warx533c8f62016-04-12 01:19:43421 mono_audio_enabled_(false),
dmazzoni756089a22016-03-15 23:55:16422 caret_highlight_enabled_(false),
423 cursor_highlight_enabled_(false),
424 focus_highlight_enabled_(false),
425 select_to_speak_enabled_(false),
426 switch_access_enabled_(false),
pkotwicz0991c822014-10-31 04:21:03427 spoken_feedback_notification_(ui::A11Y_NOTIFICATION_NONE),
[email protected]ce89d9392013-12-11 21:05:20428 should_speak_chrome_vox_announcements_on_user_screen_(true),
[email protected]a81b2c32014-03-28 06:35:01429 system_sounds_enabled_(false),
430 braille_display_connected_(false),
[email protected]2e5e0b12014-05-07 13:30:20431 scoped_braille_observer_(this),
anand.ratn04aae9ef2014-09-16 04:16:51432 braille_ime_current_(false),
dmazzoni94a4f882015-11-13 05:46:52433 chromevox_panel_(nullptr),
dtsengfb6d7cd2016-01-20 23:00:13434 extension_registry_observer_(this),
anand.ratn04aae9ef2014-09-16 04:16:51435 weak_ptr_factory_(this) {
[email protected]1dfebfc2013-06-04 03:14:32436 notification_registrar_.Add(this,
[email protected]093d9ba2013-07-23 19:26:21437 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
[email protected]e6f20642013-06-11 17:05:46438 content::NotificationService::AllSources());
439 notification_registrar_.Add(this,
[email protected]1dfebfc2013-06-04 03:14:32440 chrome::NOTIFICATION_SESSION_STARTED,
441 content::NotificationService::AllSources());
442 notification_registrar_.Add(this,
[email protected]1dfebfc2013-06-04 03:14:32443 chrome::NOTIFICATION_PROFILE_DESTROYED,
444 content::NotificationService::AllSources());
[email protected]b0a2ce32013-07-23 15:24:53445 notification_registrar_.Add(this,
446 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
447 content::NotificationService::AllSources());
[email protected]c20122572013-12-16 20:35:58448
[email protected]1488a035f2014-03-28 21:12:07449 input_method::InputMethodManager::Get()->AddObserver(this);
450
[email protected]12b0a842013-12-04 20:48:13451 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
[email protected]ce89d9392013-12-11 21:05:20452 media::SoundsManager* manager = media::SoundsManager::Get();
453 manager->Initialize(SOUND_SHUTDOWN,
454 bundle.GetRawDataResource(IDR_SOUND_SHUTDOWN_WAV));
455 manager->Initialize(
456 SOUND_SPOKEN_FEEDBACK_ENABLED,
457 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_ENABLED_WAV));
458 manager->Initialize(
459 SOUND_SPOKEN_FEEDBACK_DISABLED,
460 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_DISABLED_WAV));
[email protected]07f3ea92014-08-14 05:23:38461 manager->Initialize(SOUND_PASSTHROUGH,
462 bundle.GetRawDataResource(IDR_SOUND_PASSTHROUGH_WAV));
463 manager->Initialize(SOUND_EXIT_SCREEN,
464 bundle.GetRawDataResource(IDR_SOUND_EXIT_SCREEN_WAV));
465 manager->Initialize(SOUND_ENTER_SCREEN,
466 bundle.GetRawDataResource(IDR_SOUND_ENTER_SCREEN_WAV));
[email protected]1dfebfc2013-06-04 03:14:32467}
468
469AccessibilityManager::~AccessibilityManager() {
470 CHECK(this == g_accessibility_manager);
[email protected]d8edc9c2014-02-25 00:06:03471 AccessibilityStatusEventDetails details(
472 ACCESSIBILITY_MANAGER_SHUTDOWN,
473 false,
pkotwicz0991c822014-10-31 04:21:03474 ui::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03475 NotifyAccessibilityStatusChanged(details);
[email protected]1488a035f2014-03-28 21:12:07476 input_method::InputMethodManager::Get()->RemoveObserver(this);
dmazzoni94a4f882015-11-13 05:46:52477
478 if (chromevox_panel_) {
479 chromevox_panel_->Close();
480 chromevox_panel_ = nullptr;
481 }
[email protected]1dfebfc2013-06-04 03:14:32482}
483
[email protected]c20122572013-12-16 20:35:58484bool AccessibilityManager::ShouldShowAccessibilityMenu() {
485 // If any of the loaded profiles has an accessibility feature turned on - or
486 // enforced to always show the menu - we return true to show the menu.
487 std::vector<Profile*> profiles =
488 g_browser_process->profile_manager()->GetLoadedProfiles();
489 for (std::vector<Profile*>::iterator it = profiles.begin();
490 it != profiles.end();
491 ++it) {
492 PrefService* pref_service = (*it)->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19493 if (pref_service->GetBoolean(prefs::kAccessibilityStickyKeysEnabled) ||
494 pref_service->GetBoolean(prefs::kAccessibilityLargeCursorEnabled) ||
495 pref_service->GetBoolean(prefs::kAccessibilitySpokenFeedbackEnabled) ||
496 pref_service->GetBoolean(prefs::kAccessibilityHighContrastEnabled) ||
497 pref_service->GetBoolean(prefs::kAccessibilityAutoclickEnabled) ||
[email protected]c20122572013-12-16 20:35:58498 pref_service->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu) ||
[email protected]ced247a2014-06-13 19:14:19499 pref_service->GetBoolean(prefs::kAccessibilityScreenMagnifierEnabled) ||
warx533c8f62016-04-12 01:19:43500 pref_service->GetBoolean(prefs::kAccessibilityVirtualKeyboardEnabled) ||
501 pref_service->GetBoolean(prefs::kAccessibilityMonoAudioEnabled))
[email protected]c20122572013-12-16 20:35:58502 return true;
503 }
504 return false;
505}
506
[email protected]a4994f1e2014-02-11 18:58:16507bool AccessibilityManager::ShouldEnableCursorCompositing() {
[email protected]f74c0b9c2014-04-17 23:24:03508 if (!profile_)
509 return false;
510 PrefService* pref_service = profile_->GetPrefs();
511 // Enable cursor compositing when one or more of the listed accessibility
512 // features are turned on.
[email protected]ced247a2014-06-13 19:14:19513 if (pref_service->GetBoolean(prefs::kAccessibilityLargeCursorEnabled) ||
514 pref_service->GetBoolean(prefs::kAccessibilityHighContrastEnabled) ||
515 pref_service->GetBoolean(prefs::kAccessibilityScreenMagnifierEnabled))
[email protected]f74c0b9c2014-04-17 23:24:03516 return true;
[email protected]a4994f1e2014-02-11 18:58:16517 return false;
518}
519
[email protected]8126b812013-06-06 03:49:17520void AccessibilityManager::EnableLargeCursor(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14521 if (!profile_)
522 return;
523
524 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19525 pref_service->SetBoolean(prefs::kAccessibilityLargeCursorEnabled, enabled);
[email protected]d80f19302013-06-07 13:12:14526 pref_service->CommitPendingWrite();
527}
528
529void AccessibilityManager::UpdateLargeCursorFromPref() {
530 if (!profile_)
531 return;
532
533 const bool enabled =
[email protected]ced247a2014-06-13 19:14:19534 profile_->GetPrefs()->GetBoolean(prefs::kAccessibilityLargeCursorEnabled);
[email protected]d80f19302013-06-07 13:12:14535
[email protected]8126b812013-06-06 03:49:17536 if (large_cursor_enabled_ == enabled)
537 return;
538
539 large_cursor_enabled_ = enabled;
540
[email protected]d8edc9c2014-02-25 00:06:03541 AccessibilityStatusEventDetails details(
542 ACCESSIBILITY_TOGGLE_LARGE_CURSOR,
543 enabled,
pkotwicz0991c822014-10-31 04:21:03544 ui::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03545
546 NotifyAccessibilityStatusChanged(details);
[email protected]846be6e2013-06-07 08:03:26547
[email protected]a7c93e32013-09-03 08:50:30548 ash::Shell::GetInstance()->cursor_manager()->SetCursorSet(
549 enabled ? ui::CURSOR_SET_LARGE : ui::CURSOR_SET_NORMAL);
[email protected]87ec2202014-02-06 06:24:27550 ash::Shell::GetInstance()->SetCursorCompositingEnabled(
[email protected]a4994f1e2014-02-11 18:58:16551 ShouldEnableCursorCompositing());
[email protected]8126b812013-06-06 03:49:17552}
553
[email protected]5ecf6122013-10-31 12:24:09554bool AccessibilityManager::IsIncognitoAllowed() {
gogeralddde4ee02015-08-26 18:58:49555 return profile_ != NULL &&
556 profile_->GetProfileType() != Profile::GUEST_PROFILE &&
557 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) !=
558 IncognitoModePrefs::DISABLED;
[email protected]5ecf6122013-10-31 12:24:09559}
560
[email protected]8126b812013-06-06 03:49:17561bool AccessibilityManager::IsLargeCursorEnabled() {
562 return large_cursor_enabled_;
563}
564
[email protected]93a534e2013-06-20 16:41:44565void AccessibilityManager::EnableStickyKeys(bool enabled) {
566 if (!profile_)
567 return;
568 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19569 pref_service->SetBoolean(prefs::kAccessibilityStickyKeysEnabled, enabled);
[email protected]93a534e2013-06-20 16:41:44570 pref_service->CommitPendingWrite();
571}
572
573bool AccessibilityManager::IsStickyKeysEnabled() {
574 return sticky_keys_enabled_;
575}
576
577void AccessibilityManager::UpdateStickyKeysFromPref() {
578 if (!profile_)
579 return;
580
581 const bool enabled =
[email protected]ced247a2014-06-13 19:14:19582 profile_->GetPrefs()->GetBoolean(prefs::kAccessibilityStickyKeysEnabled);
[email protected]93a534e2013-06-20 16:41:44583
584 if (sticky_keys_enabled_ == enabled)
585 return;
586
587 sticky_keys_enabled_ = enabled;
[email protected]08bdabed2013-12-20 07:52:28588 ash::Shell::GetInstance()->sticky_keys_controller()->Enable(enabled);
[email protected]93a534e2013-06-20 16:41:44589}
590
[email protected]1dfebfc2013-06-04 03:14:32591void AccessibilityManager::EnableSpokenFeedback(
592 bool enabled,
pkotwicz0991c822014-10-31 04:21:03593 ui::AccessibilityNotificationVisibility notify) {
[email protected]1dfebfc2013-06-04 03:14:32594 if (!profile_)
595 return;
[email protected]5d2ea362013-12-13 08:10:18596 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
597 enabled ? ash::UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK
598 : ash::UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK);
599
[email protected]d80f19302013-06-07 13:12:14600 spoken_feedback_notification_ = notify;
601
[email protected]1dfebfc2013-06-04 03:14:32602 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19603 pref_service->SetBoolean(prefs::kAccessibilitySpokenFeedbackEnabled, enabled);
[email protected]1dfebfc2013-06-04 03:14:32604 pref_service->CommitPendingWrite();
[email protected]d80f19302013-06-07 13:12:14605
pkotwicz0991c822014-10-31 04:21:03606 spoken_feedback_notification_ = ui::A11Y_NOTIFICATION_NONE;
[email protected]d80f19302013-06-07 13:12:14607}
608
609void AccessibilityManager::UpdateSpokenFeedbackFromPref() {
610 if (!profile_)
611 return;
612
[email protected]ced247a2014-06-13 19:14:19613 const bool enabled = profile_->GetPrefs()->GetBoolean(
614 prefs::kAccessibilitySpokenFeedbackEnabled);
[email protected]d80f19302013-06-07 13:12:14615
616 if (spoken_feedback_enabled_ == enabled)
617 return;
618
619 spoken_feedback_enabled_ = enabled;
620
[email protected]d8edc9c2014-02-25 00:06:03621 AccessibilityStatusEventDetails details(
622 ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK,
623 enabled,
624 spoken_feedback_notification_);
625
626 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32627
[email protected]0e9504d2013-11-05 02:33:29628 if (enabled) {
[email protected]b0a2ce32013-07-23 15:24:53629 LoadChromeVox();
[email protected]0e9504d2013-11-05 02:33:29630 } else {
[email protected]ee8bbd972014-02-03 06:52:47631 UnloadChromeVox();
[email protected]0e9504d2013-11-05 02:33:29632 }
[email protected]2e5e0b12014-05-07 13:30:20633 UpdateBrailleImeState();
[email protected]b0a2ce32013-07-23 15:24:53634}
635
636void AccessibilityManager::LoadChromeVox() {
[email protected]44beb032014-06-11 06:24:37637 base::Closure done_cb = base::Bind(&AccessibilityManager::PostLoadChromeVox,
638 weak_ptr_factory_.GetWeakPtr(),
639 profile_);
[email protected]b0a2ce32013-07-23 15:24:53640 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker();
641 if (screen_locker && screen_locker->locked()) {
642 // If on the lock screen, loads ChromeVox only to the lock screen as for
643 // now. On unlock, it will be loaded to the user screen.
644 // (see. AccessibilityManager::Observe())
[email protected]44beb032014-06-11 06:24:37645 LoadChromeVoxToLockScreen(done_cb);
[email protected]ee8bbd972014-02-03 06:52:47646 } else {
[email protected]44beb032014-06-11 06:24:37647 LoadChromeVoxToUserScreen(done_cb);
[email protected]b0a2ce32013-07-23 15:24:53648 }
[email protected]b0a2ce32013-07-23 15:24:53649}
650
[email protected]44beb032014-06-11 06:24:37651void AccessibilityManager::LoadChromeVoxToUserScreen(
652 const base::Closure& done_cb) {
[email protected]b0a2ce32013-07-23 15:24:53653 if (chrome_vox_loaded_on_user_screen_)
654 return;
655
656 // Determine whether an OOBE screen is currently being shown. If so,
657 // ChromeVox will be injected directly into that screen.
[email protected]681d0532013-06-11 12:52:50658 content::WebUI* login_web_ui = NULL;
[email protected]681d0532013-06-11 12:52:50659
[email protected]b0a2ce32013-07-23 15:24:53660 if (ProfileHelper::IsSigninProfile(profile_)) {
jdufault314f0692016-01-23 02:14:24661 LoginDisplayHost* login_display_host = LoginDisplayHost::default_host();
[email protected]b0a2ce32013-07-23 15:24:53662 if (login_display_host) {
663 WebUILoginView* web_ui_login_view =
664 login_display_host->GetWebUILoginView();
665 if (web_ui_login_view)
666 login_web_ui = web_ui_login_view->GetWebUI();
[email protected]1dfebfc2013-06-04 03:14:32667 }
[email protected]a4846a02014-04-21 19:11:45668
669 // Lock screen uses the signin progile.
670 chrome_vox_loaded_on_lock_screen_ = true;
[email protected]1dfebfc2013-06-04 03:14:32671 }
[email protected]b0a2ce32013-07-23 15:24:53672
[email protected]b0a2ce32013-07-23 15:24:53673 chrome_vox_loaded_on_user_screen_ = true;
[email protected]44beb032014-06-11 06:24:37674 LoadChromeVoxExtension(
675 profile_, login_web_ui ?
676 login_web_ui->GetWebContents()->GetRenderViewHost() : NULL,
677 done_cb);
[email protected]b0a2ce32013-07-23 15:24:53678}
679
[email protected]44beb032014-06-11 06:24:37680void AccessibilityManager::LoadChromeVoxToLockScreen(
681 const base::Closure& done_cb) {
[email protected]b0a2ce32013-07-23 15:24:53682 if (chrome_vox_loaded_on_lock_screen_)
683 return;
684
685 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker();
686 if (screen_locker && screen_locker->locked()) {
687 content::WebUI* lock_web_ui = screen_locker->GetAssociatedWebUI();
688 if (lock_web_ui) {
689 Profile* profile = Profile::FromWebUI(lock_web_ui);
[email protected]b0a2ce32013-07-23 15:24:53690 chrome_vox_loaded_on_lock_screen_ = true;
[email protected]44beb032014-06-11 06:24:37691 LoadChromeVoxExtension(
692 profile,
693 lock_web_ui->GetWebContents()->GetRenderViewHost(),
694 done_cb);
[email protected]b0a2ce32013-07-23 15:24:53695 }
696 }
697}
698
699void AccessibilityManager::UnloadChromeVox() {
dmazzoni94a4f882015-11-13 05:46:52700 if (chromevox_panel_) {
701 chromevox_panel_->Close();
702 chromevox_panel_ = nullptr;
703 }
704
[email protected]b0a2ce32013-07-23 15:24:53705 if (chrome_vox_loaded_on_lock_screen_)
706 UnloadChromeVoxFromLockScreen();
707
708 if (chrome_vox_loaded_on_user_screen_) {
709 UnloadChromeVoxExtension(profile_);
710 chrome_vox_loaded_on_user_screen_ = false;
711 }
[email protected]ee8bbd972014-02-03 06:52:47712
713 PostUnloadChromeVox(profile_);
[email protected]b0a2ce32013-07-23 15:24:53714}
715
716void AccessibilityManager::UnloadChromeVoxFromLockScreen() {
717 // Lock screen uses the signin progile.
718 Profile* signin_profile = ProfileHelper::GetSigninProfile();
719 UnloadChromeVoxExtension(signin_profile);
720 chrome_vox_loaded_on_lock_screen_ = false;
[email protected]1dfebfc2013-06-04 03:14:32721}
722
723bool AccessibilityManager::IsSpokenFeedbackEnabled() {
724 return spoken_feedback_enabled_;
725}
726
727void AccessibilityManager::ToggleSpokenFeedback(
pkotwicz0991c822014-10-31 04:21:03728 ui::AccessibilityNotificationVisibility notify) {
[email protected]681d0532013-06-11 12:52:50729 EnableSpokenFeedback(!IsSpokenFeedbackEnabled(), notify);
[email protected]1dfebfc2013-06-04 03:14:32730}
731
[email protected]1dfebfc2013-06-04 03:14:32732void AccessibilityManager::EnableHighContrast(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14733 if (!profile_)
734 return;
735
736 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19737 pref_service->SetBoolean(prefs::kAccessibilityHighContrastEnabled, enabled);
[email protected]d80f19302013-06-07 13:12:14738 pref_service->CommitPendingWrite();
739}
740
741void AccessibilityManager::UpdateHighContrastFromPref() {
742 if (!profile_)
743 return;
744
[email protected]ced247a2014-06-13 19:14:19745 const bool enabled = profile_->GetPrefs()->GetBoolean(
746 prefs::kAccessibilityHighContrastEnabled);
[email protected]d80f19302013-06-07 13:12:14747
[email protected]1dfebfc2013-06-04 03:14:32748 if (high_contrast_enabled_ == enabled)
749 return;
750
751 high_contrast_enabled_ = enabled;
752
[email protected]d8edc9c2014-02-25 00:06:03753 AccessibilityStatusEventDetails details(
754 ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE,
755 enabled,
pkotwicz0991c822014-10-31 04:21:03756 ui::A11Y_NOTIFICATION_NONE);
[email protected]d8edc9c2014-02-25 00:06:03757
758 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32759
[email protected]1dfebfc2013-06-04 03:14:32760 ash::Shell::GetInstance()->high_contrast_controller()->SetEnabled(enabled);
[email protected]87ec2202014-02-06 06:24:27761 ash::Shell::GetInstance()->SetCursorCompositingEnabled(
[email protected]a4994f1e2014-02-11 18:58:16762 ShouldEnableCursorCompositing());
[email protected]1dfebfc2013-06-04 03:14:32763}
764
[email protected]628b8902014-03-12 05:26:41765void AccessibilityManager::OnLocaleChanged() {
[email protected]d1d5f4f2013-06-14 07:17:09766 if (!profile_)
767 return;
768
769 if (!IsSpokenFeedbackEnabled())
770 return;
771
772 // If the system locale changes and spoken feedback is enabled,
773 // reload ChromeVox so that it switches its internal translations
774 // to the new language.
pkotwicz0991c822014-10-31 04:21:03775 EnableSpokenFeedback(false, ui::A11Y_NOTIFICATION_NONE);
776 EnableSpokenFeedback(true, ui::A11Y_NOTIFICATION_NONE);
[email protected]d1d5f4f2013-06-14 07:17:09777}
778
[email protected]07f3ea92014-08-14 05:23:38779void AccessibilityManager::PlayEarcon(int sound_key) {
780 DCHECK(sound_key < chromeos::SOUND_COUNT);
781 ash::PlaySystemSoundIfSpokenFeedback(sound_key);
782}
783
dmazzoni82ef29a2016-05-10 23:37:51784void AccessibilityManager::HandleAccessibilityGesture(ui::AXGesture gesture) {
785 extensions::EventRouter* event_router =
786 extensions::EventRouter::Get(profile());
787 CHECK(event_router);
788
789 std::unique_ptr<base::ListValue> event_args(new base::ListValue());
790 event_args->AppendString(ui::ToString(gesture));
791 std::unique_ptr<extensions::Event> event(new extensions::Event(
792 extensions::events::ACCESSIBILITY_PRIVATE_ON_ACCESSIBILITY_GESTURE,
793 extensions::api::accessibility_private::OnAccessibilityGesture::
794 kEventName,
795 std::move(event_args)));
796 event_router->DispatchEventWithLazyListener(
797 extension_misc::kChromeVoxExtensionId, std::move(event));
798}
799
dmazzoniff86e3472016-06-03 19:52:32800void AccessibilityManager::SetTouchAccessibilityAnchorPoint(
801 const gfx::Point& anchor_point) {
802 ash::RootWindowController* root_window_controller =
803 ash::RootWindowController::ForTargetRootWindow();
804 root_window_controller->SetTouchAccessibilityAnchorPoint(anchor_point);
805}
806
[email protected]1dfebfc2013-06-04 03:14:32807bool AccessibilityManager::IsHighContrastEnabled() {
808 return high_contrast_enabled_;
809}
810
[email protected]1c881562013-10-12 07:52:58811void AccessibilityManager::EnableAutoclick(bool enabled) {
812 if (!profile_)
813 return;
814
815 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19816 pref_service->SetBoolean(prefs::kAccessibilityAutoclickEnabled, enabled);
[email protected]1c881562013-10-12 07:52:58817 pref_service->CommitPendingWrite();
818}
819
820bool AccessibilityManager::IsAutoclickEnabled() {
821 return autoclick_enabled_;
822}
823
824void AccessibilityManager::UpdateAutoclickFromPref() {
ginkagebda078c2014-12-15 14:24:53825 if (!profile_)
826 return;
827
[email protected]1c881562013-10-12 07:52:58828 bool enabled =
[email protected]ced247a2014-06-13 19:14:19829 profile_->GetPrefs()->GetBoolean(prefs::kAccessibilityAutoclickEnabled);
[email protected]1c881562013-10-12 07:52:58830
831 if (autoclick_enabled_ == enabled)
832 return;
833 autoclick_enabled_ = enabled;
834
[email protected]1c881562013-10-12 07:52:58835 ash::Shell::GetInstance()->autoclick_controller()->SetEnabled(enabled);
[email protected]1c881562013-10-12 07:52:58836}
837
[email protected]84d652d2013-10-23 13:57:57838void AccessibilityManager::SetAutoclickDelay(int delay_ms) {
839 if (!profile_)
840 return;
841
842 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19843 pref_service->SetInteger(prefs::kAccessibilityAutoclickDelayMs, delay_ms);
[email protected]84d652d2013-10-23 13:57:57844 pref_service->CommitPendingWrite();
845}
846
847int AccessibilityManager::GetAutoclickDelay() const {
848 return autoclick_delay_ms_;
849}
850
851void AccessibilityManager::UpdateAutoclickDelayFromPref() {
ginkagebda078c2014-12-15 14:24:53852 if (!profile_)
853 return;
854
[email protected]84d652d2013-10-23 13:57:57855 int autoclick_delay_ms =
[email protected]ced247a2014-06-13 19:14:19856 profile_->GetPrefs()->GetInteger(prefs::kAccessibilityAutoclickDelayMs);
[email protected]84d652d2013-10-23 13:57:57857
858 if (autoclick_delay_ms == autoclick_delay_ms_)
859 return;
860 autoclick_delay_ms_ = autoclick_delay_ms;
861
[email protected]84d652d2013-10-23 13:57:57862 ash::Shell::GetInstance()->autoclick_controller()->SetAutoclickDelay(
863 autoclick_delay_ms_);
[email protected]84d652d2013-10-23 13:57:57864}
865
[email protected]e1b299b2014-01-29 23:53:41866void AccessibilityManager::EnableVirtualKeyboard(bool enabled) {
867 if (!profile_)
868 return;
869
870 PrefService* pref_service = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:19871 pref_service->SetBoolean(prefs::kAccessibilityVirtualKeyboardEnabled,
872 enabled);
[email protected]e1b299b2014-01-29 23:53:41873 pref_service->CommitPendingWrite();
874}
875
876bool AccessibilityManager::IsVirtualKeyboardEnabled() {
877 return virtual_keyboard_enabled_;
878}
879
880void AccessibilityManager::UpdateVirtualKeyboardFromPref() {
881 if (!profile_)
882 return;
883
[email protected]ced247a2014-06-13 19:14:19884 const bool enabled = profile_->GetPrefs()->GetBoolean(
885 prefs::kAccessibilityVirtualKeyboardEnabled);
[email protected]e1b299b2014-01-29 23:53:41886
887 if (virtual_keyboard_enabled_ == enabled)
888 return;
889 virtual_keyboard_enabled_ = enabled;
890
[email protected]e1b299b2014-01-29 23:53:41891 keyboard::SetAccessibilityKeyboardEnabled(enabled);
[email protected]ff0eb112014-05-07 13:31:35892 // Note that there are two versions of the on-screen keyboard. A full layout
893 // is provided for accessibility, which includes sticky modifier keys to
894 // enable typing of hotkeys. A compact version is used in touchview mode
895 // to provide a layout with larger keys to facilitate touch typing. In the
896 // event that the a11y keyboard is being disabled, an on-screen keyboard might
897 // still be enabled and a forced reset is required to pick up the layout
898 // change.
899 if (keyboard::IsKeyboardEnabled())
[email protected]e1b299b2014-01-29 23:53:41900 ash::Shell::GetInstance()->CreateKeyboard();
[email protected]ff0eb112014-05-07 13:31:35901 else
[email protected]e1b299b2014-01-29 23:53:41902 ash::Shell::GetInstance()->DeactivateKeyboard();
rsadama1104b82014-11-03 20:50:52903
904 AccessibilityStatusEventDetails details(
905 ACCESSIBILITY_TOGGLE_VIRTUAL_KEYBOARD,
906 enabled,
907 ui::A11Y_NOTIFICATION_NONE);
908 NotifyAccessibilityStatusChanged(details);
[email protected]e1b299b2014-01-29 23:53:41909}
910
warx533c8f62016-04-12 01:19:43911void AccessibilityManager::EnableMonoAudio(bool enabled) {
912 if (!profile_)
913 return;
914
915 PrefService* pref_service = profile_->GetPrefs();
916 pref_service->SetBoolean(prefs::kAccessibilityMonoAudioEnabled,
917 enabled);
918 pref_service->CommitPendingWrite();
919}
920
921bool AccessibilityManager::IsMonoAudioEnabled() {
922 return mono_audio_enabled_;
923}
924
925void AccessibilityManager::UpdateMonoAudioFromPref() {
926 if (!profile_)
927 return;
928
929 const bool enabled = profile_->GetPrefs()->GetBoolean(
930 prefs::kAccessibilityMonoAudioEnabled);
931
932 if (mono_audio_enabled_ == enabled)
933 return;
934 mono_audio_enabled_ = enabled;
935
936 AccessibilityStatusEventDetails details(
937 ACCESSIBILITY_TOGGLE_MONO_AUDIO,
938 enabled,
939 ui::A11Y_NOTIFICATION_NONE);
940 NotifyAccessibilityStatusChanged(details);
941
942 ash::Shell::GetInstance()->audio_a11y_controller()->SetOutputMono(enabled);
943}
944
dmazzoni756089a22016-03-15 23:55:16945void AccessibilityManager::SetCaretHighlightEnabled(bool enabled) {
946 if (!profile_)
947 return;
948
949 PrefService* pref_service = profile_->GetPrefs();
950 pref_service->SetBoolean(prefs::kAccessibilityCaretHighlightEnabled, enabled);
951 pref_service->CommitPendingWrite();
952}
953
954bool AccessibilityManager::IsCaretHighlightEnabled() const {
955 return caret_highlight_enabled_;
956}
957
958void AccessibilityManager::UpdateCaretHighlightFromPref() {
959 if (!profile_)
960 return;
961
962 const bool enabled = profile_->GetPrefs()->GetBoolean(
963 prefs::kAccessibilityCaretHighlightEnabled);
964
965 if (caret_highlight_enabled_ == enabled)
966 return;
967 caret_highlight_enabled_ = enabled;
968
dmazzonib93107c2016-03-22 21:51:18969 UpdateAccessibilityHighlightingFromPrefs();
dmazzoni756089a22016-03-15 23:55:16970}
971
972void AccessibilityManager::SetCursorHighlightEnabled(bool enabled) {
973 if (!profile_)
974 return;
975
976 PrefService* pref_service = profile_->GetPrefs();
977 pref_service->SetBoolean(prefs::kAccessibilityCursorHighlightEnabled,
978 enabled);
979 pref_service->CommitPendingWrite();
980}
981
982bool AccessibilityManager::IsCursorHighlightEnabled() const {
983 return cursor_highlight_enabled_;
984}
985
986void AccessibilityManager::UpdateCursorHighlightFromPref() {
987 if (!profile_)
988 return;
989
990 const bool enabled = profile_->GetPrefs()->GetBoolean(
991 prefs::kAccessibilityCursorHighlightEnabled);
992
993 if (cursor_highlight_enabled_ == enabled)
994 return;
995 cursor_highlight_enabled_ = enabled;
996
dmazzonib93107c2016-03-22 21:51:18997 UpdateAccessibilityHighlightingFromPrefs();
dmazzoni756089a22016-03-15 23:55:16998}
999
1000void AccessibilityManager::SetFocusHighlightEnabled(bool enabled) {
1001 if (!profile_)
1002 return;
1003
1004 PrefService* pref_service = profile_->GetPrefs();
1005 pref_service->SetBoolean(prefs::kAccessibilityFocusHighlightEnabled, enabled);
1006 pref_service->CommitPendingWrite();
1007}
1008
1009bool AccessibilityManager::IsFocusHighlightEnabled() const {
1010 return focus_highlight_enabled_;
1011}
1012
1013void AccessibilityManager::UpdateFocusHighlightFromPref() {
1014 if (!profile_)
1015 return;
1016
1017 const bool enabled = profile_->GetPrefs()->GetBoolean(
1018 prefs::kAccessibilityFocusHighlightEnabled);
1019
1020 if (focus_highlight_enabled_ == enabled)
1021 return;
1022 focus_highlight_enabled_ = enabled;
1023
dmazzonib93107c2016-03-22 21:51:181024 UpdateAccessibilityHighlightingFromPrefs();
dmazzoni756089a22016-03-15 23:55:161025}
1026
1027void AccessibilityManager::SetSelectToSpeakEnabled(bool enabled) {
1028 if (!profile_)
1029 return;
1030
1031 PrefService* pref_service = profile_->GetPrefs();
1032 pref_service->SetBoolean(prefs::kAccessibilitySelectToSpeakEnabled, enabled);
1033 pref_service->CommitPendingWrite();
1034}
1035
1036bool AccessibilityManager::IsSelectToSpeakEnabled() const {
1037 return select_to_speak_enabled_;
1038}
1039
1040void AccessibilityManager::UpdateSelectToSpeakFromPref() {
1041 if (!profile_)
1042 return;
1043
1044 const bool enabled = profile_->GetPrefs()->GetBoolean(
1045 prefs::kAccessibilitySelectToSpeakEnabled);
1046
1047 if (select_to_speak_enabled_ == enabled)
1048 return;
1049 select_to_speak_enabled_ = enabled;
1050
1051 // TODO(dmazzoni): implement feature here.
1052}
1053
1054void AccessibilityManager::SetSwitchAccessEnabled(bool enabled) {
1055 if (!profile_)
1056 return;
1057
1058 PrefService* pref_service = profile_->GetPrefs();
1059 pref_service->SetBoolean(prefs::kAccessibilitySwitchAccessEnabled, enabled);
1060 pref_service->CommitPendingWrite();
1061}
1062
1063bool AccessibilityManager::IsSwitchAccessEnabled() const {
1064 return switch_access_enabled_;
1065}
1066
1067void AccessibilityManager::UpdateSwitchAccessFromPref() {
1068 if (!profile_)
1069 return;
1070
1071 const bool enabled = profile_->GetPrefs()->GetBoolean(
1072 prefs::kAccessibilitySwitchAccessEnabled);
1073
1074 if (switch_access_enabled_ == enabled)
1075 return;
1076 switch_access_enabled_ = enabled;
1077
1078 // TODO(dmazzoni): implement feature here.
1079}
1080
dmazzonib93107c2016-03-22 21:51:181081void AccessibilityManager::UpdateAccessibilityHighlightingFromPrefs() {
1082 if (!focus_highlight_enabled_ && !caret_highlight_enabled_ &&
1083 !cursor_highlight_enabled_) {
1084 if (accessibility_highlight_manager_)
1085 accessibility_highlight_manager_.reset();
1086 return;
1087 }
1088
1089 if (!accessibility_highlight_manager_)
1090 accessibility_highlight_manager_.reset(new AccessibilityHighlightManager());
1091
1092 accessibility_highlight_manager_->HighlightFocus(focus_highlight_enabled_);
1093 accessibility_highlight_manager_->HighlightCaret(caret_highlight_enabled_);
1094 accessibility_highlight_manager_->HighlightCursor(cursor_highlight_enabled_);
1095}
1096
[email protected]a81b2c32014-03-28 06:35:011097bool AccessibilityManager::IsBrailleDisplayConnected() const {
1098 return braille_display_connected_;
1099}
1100
[email protected]8c79e3f2013-10-30 01:05:141101void AccessibilityManager::CheckBrailleState() {
[email protected]a81b2c32014-03-28 06:35:011102 BrailleController* braille_controller = GetBrailleController();
1103 if (!scoped_braille_observer_.IsObserving(braille_controller))
1104 scoped_braille_observer_.Add(braille_controller);
[email protected]8c79e3f2013-10-30 01:05:141105 BrowserThread::PostTaskAndReplyWithResult(
[email protected]a81b2c32014-03-28 06:35:011106 BrowserThread::IO,
1107 FROM_HERE,
1108 base::Bind(&BrailleController::GetDisplayState,
1109 base::Unretained(braille_controller)),
[email protected]8c79e3f2013-10-30 01:05:141110 base::Bind(&AccessibilityManager::ReceiveBrailleDisplayState,
1111 weak_ptr_factory_.GetWeakPtr()));
1112}
1113
1114void AccessibilityManager::ReceiveBrailleDisplayState(
dcheng24002d02016-04-08 02:42:401115 std::unique_ptr<extensions::api::braille_display_private::DisplayState>
1116 state) {
[email protected]2e5e0b12014-05-07 13:30:201117 OnBrailleDisplayStateChanged(*state);
1118}
1119
1120void AccessibilityManager::UpdateBrailleImeState() {
1121 if (!profile_)
1122 return;
1123 PrefService* pref_service = profile_->GetPrefs();
brettwc6f82b12015-07-21 21:37:381124 std::vector<std::string> preload_engines =
1125 base::SplitString(pref_service->GetString(prefs::kLanguagePreloadEngines),
1126 ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
[email protected]2e5e0b12014-05-07 13:30:201127 std::vector<std::string>::iterator it =
1128 std::find(preload_engines.begin(),
1129 preload_engines.end(),
1130 extension_misc::kBrailleImeEngineId);
1131 bool is_enabled = (it != preload_engines.end());
1132 bool should_be_enabled =
1133 (spoken_feedback_enabled_ && braille_display_connected_);
1134 if (is_enabled == should_be_enabled)
1135 return;
1136 if (should_be_enabled)
1137 preload_engines.push_back(extension_misc::kBrailleImeEngineId);
1138 else
1139 preload_engines.erase(it);
1140 pref_service->SetString(prefs::kLanguagePreloadEngines,
brettwd94a22142015-07-15 05:19:261141 base::JoinString(preload_engines, ","));
[email protected]2e5e0b12014-05-07 13:30:201142 braille_ime_current_ = false;
[email protected]8c79e3f2013-10-30 01:05:141143}
1144
[email protected]1488a035f2014-03-28 21:12:071145// Overridden from InputMethodManager::Observer.
1146void AccessibilityManager::InputMethodChanged(
1147 input_method::InputMethodManager* manager,
alematef06730292015-05-12 21:36:071148 Profile* /* profile */,
[email protected]1488a035f2014-03-28 21:12:071149 bool show_message) {
[email protected]1488a035f2014-03-28 21:12:071150 // Sticky keys is implemented only in ash.
dpolukhin04e5b8092014-09-11 02:55:051151 // TODO(dpolukhin): support Athena, crbug.com/408733.
[email protected]1488a035f2014-03-28 21:12:071152 ash::Shell::GetInstance()->sticky_keys_controller()->SetModifiersEnabled(
1153 manager->IsISOLevel5ShiftUsedByCurrentInputMethod(),
1154 manager->IsAltGrUsedByCurrentInputMethod());
[email protected]2e5e0b12014-05-07 13:30:201155 const chromeos::input_method::InputMethodDescriptor descriptor =
[email protected]f0881cf2014-08-15 23:31:421156 manager->GetActiveIMEState()->GetCurrentInputMethod();
[email protected]2e5e0b12014-05-07 13:30:201157 braille_ime_current_ =
1158 (descriptor.id() == extension_misc::kBrailleImeEngineId);
[email protected]1488a035f2014-03-28 21:12:071159}
[email protected]8c79e3f2013-10-30 01:05:141160
[email protected]1dfebfc2013-06-04 03:14:321161void AccessibilityManager::SetProfile(Profile* profile) {
1162 pref_change_registrar_.reset();
[email protected]d1d5f4f2013-06-14 07:17:091163 local_state_pref_change_registrar_.reset();
[email protected]1dfebfc2013-06-04 03:14:321164
1165 if (profile) {
[email protected]0aae2fe2013-07-05 07:04:421166 // TODO(yoshiki): Move following code to PrefHandler.
[email protected]1dfebfc2013-06-04 03:14:321167 pref_change_registrar_.reset(new PrefChangeRegistrar);
1168 pref_change_registrar_->Init(profile->GetPrefs());
1169 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191170 prefs::kAccessibilityLargeCursorEnabled,
[email protected]d80f19302013-06-07 13:12:141171 base::Bind(&AccessibilityManager::UpdateLargeCursorFromPref,
[email protected]8126b812013-06-06 03:49:171172 base::Unretained(this)));
1173 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191174 prefs::kAccessibilityStickyKeysEnabled,
[email protected]93a534e2013-06-20 16:41:441175 base::Bind(&AccessibilityManager::UpdateStickyKeysFromPref,
1176 base::Unretained(this)));
1177 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191178 prefs::kAccessibilitySpokenFeedbackEnabled,
[email protected]d80f19302013-06-07 13:12:141179 base::Bind(&AccessibilityManager::UpdateSpokenFeedbackFromPref,
[email protected]1dfebfc2013-06-04 03:14:321180 base::Unretained(this)));
1181 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191182 prefs::kAccessibilityHighContrastEnabled,
[email protected]d80f19302013-06-07 13:12:141183 base::Bind(&AccessibilityManager::UpdateHighContrastFromPref,
[email protected]1dfebfc2013-06-04 03:14:321184 base::Unretained(this)));
[email protected]1c881562013-10-12 07:52:581185 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191186 prefs::kAccessibilityAutoclickEnabled,
[email protected]1c881562013-10-12 07:52:581187 base::Bind(&AccessibilityManager::UpdateAutoclickFromPref,
1188 base::Unretained(this)));
[email protected]84d652d2013-10-23 13:57:571189 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191190 prefs::kAccessibilityAutoclickDelayMs,
[email protected]84d652d2013-10-23 13:57:571191 base::Bind(&AccessibilityManager::UpdateAutoclickDelayFromPref,
1192 base::Unretained(this)));
[email protected]e1b299b2014-01-29 23:53:411193 pref_change_registrar_->Add(
[email protected]ced247a2014-06-13 19:14:191194 prefs::kAccessibilityVirtualKeyboardEnabled,
[email protected]e1b299b2014-01-29 23:53:411195 base::Bind(&AccessibilityManager::UpdateVirtualKeyboardFromPref,
1196 base::Unretained(this)));
dmazzoni756089a22016-03-15 23:55:161197 pref_change_registrar_->Add(
warx533c8f62016-04-12 01:19:431198 prefs::kAccessibilityMonoAudioEnabled,
1199 base::Bind(&AccessibilityManager::UpdateMonoAudioFromPref,
1200 base::Unretained(this)));
1201 pref_change_registrar_->Add(
dmazzoni756089a22016-03-15 23:55:161202 prefs::kAccessibilityCaretHighlightEnabled,
1203 base::Bind(&AccessibilityManager::UpdateCaretHighlightFromPref,
1204 base::Unretained(this)));
1205 pref_change_registrar_->Add(
1206 prefs::kAccessibilityCursorHighlightEnabled,
1207 base::Bind(&AccessibilityManager::UpdateCursorHighlightFromPref,
1208 base::Unretained(this)));
1209 pref_change_registrar_->Add(
1210 prefs::kAccessibilityFocusHighlightEnabled,
1211 base::Bind(&AccessibilityManager::UpdateFocusHighlightFromPref,
1212 base::Unretained(this)));
1213 pref_change_registrar_->Add(
1214 prefs::kAccessibilitySelectToSpeakEnabled,
1215 base::Bind(&AccessibilityManager::UpdateSelectToSpeakFromPref,
1216 base::Unretained(this)));
1217 pref_change_registrar_->Add(
1218 prefs::kAccessibilitySwitchAccessEnabled,
1219 base::Bind(&AccessibilityManager::UpdateSwitchAccessFromPref,
1220 base::Unretained(this)));
[email protected]1dfebfc2013-06-04 03:14:321221
[email protected]d1d5f4f2013-06-14 07:17:091222 local_state_pref_change_registrar_.reset(new PrefChangeRegistrar);
1223 local_state_pref_change_registrar_->Init(g_browser_process->local_state());
1224 local_state_pref_change_registrar_->Add(
1225 prefs::kApplicationLocale,
[email protected]628b8902014-03-12 05:26:411226 base::Bind(&AccessibilityManager::OnLocaleChanged,
[email protected]d1d5f4f2013-06-14 07:17:091227 base::Unretained(this)));
1228
[email protected]1dfebfc2013-06-04 03:14:321229 content::BrowserAccessibilityState::GetInstance()->AddHistogramCallback(
1230 base::Bind(
1231 &AccessibilityManager::UpdateChromeOSAccessibilityHistograms,
1232 base::Unretained(this)));
1233 }
1234
[email protected]0aae2fe2013-07-05 07:04:421235 large_cursor_pref_handler_.HandleProfileChanged(profile_, profile);
1236 spoken_feedback_pref_handler_.HandleProfileChanged(profile_, profile);
1237 high_contrast_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]1c881562013-10-12 07:52:581238 autoclick_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]84d652d2013-10-23 13:57:571239 autoclick_delay_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]42b471f2014-01-31 20:31:291240 virtual_keyboard_pref_handler_.HandleProfileChanged(profile_, profile);
warx533c8f62016-04-12 01:19:431241 mono_audio_pref_handler_.HandleProfileChanged(profile_, profile);
dmazzoni756089a22016-03-15 23:55:161242 caret_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
1243 cursor_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
1244 focus_highlight_pref_handler_.HandleProfileChanged(profile_, profile);
1245 select_to_speak_pref_handler_.HandleProfileChanged(profile_, profile);
1246 switch_access_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]0aae2fe2013-07-05 07:04:421247
[email protected]a81b2c32014-03-28 06:35:011248 bool had_profile = (profile_ != NULL);
1249 profile_ = profile;
1250
1251 if (!had_profile && profile)
[email protected]8c79e3f2013-10-30 01:05:141252 CheckBrailleState();
[email protected]2e5e0b12014-05-07 13:30:201253 else
1254 UpdateBrailleImeState();
[email protected]d80f19302013-06-07 13:12:141255 UpdateLargeCursorFromPref();
[email protected]93a534e2013-06-20 16:41:441256 UpdateStickyKeysFromPref();
[email protected]d80f19302013-06-07 13:12:141257 UpdateSpokenFeedbackFromPref();
1258 UpdateHighContrastFromPref();
[email protected]1c881562013-10-12 07:52:581259 UpdateAutoclickFromPref();
[email protected]84d652d2013-10-23 13:57:571260 UpdateAutoclickDelayFromPref();
[email protected]e1b299b2014-01-29 23:53:411261 UpdateVirtualKeyboardFromPref();
warx533c8f62016-04-12 01:19:431262 UpdateMonoAudioFromPref();
dmazzoni756089a22016-03-15 23:55:161263 UpdateCaretHighlightFromPref();
1264 UpdateCursorHighlightFromPref();
1265 UpdateFocusHighlightFromPref();
1266 UpdateSelectToSpeakFromPref();
1267 UpdateSwitchAccessFromPref();
dmazzoni39d6d4b2016-03-29 22:18:001268
1269 // Update the panel height in the shelf layout manager when the profile
1270 // changes, since the shelf layout manager doesn't exist in the login profile.
1271 if (chromevox_panel_)
1272 chromevox_panel_->UpdatePanelHeight();
[email protected]1dfebfc2013-06-04 03:14:321273}
1274
alematecdf46dd2015-11-12 03:15:161275void AccessibilityManager::ActiveUserChanged(const AccountId& account_id) {
[email protected]c20122572013-12-16 20:35:581276 SetProfile(ProfileManager::GetActiveUserProfile());
1277}
1278
achuithecf113f2015-09-10 10:09:191279void AccessibilityManager::OnAppTerminating() {
1280 session_state_observer_.reset();
1281}
1282
dmazzonid47388d2016-03-31 16:03:511283void AccessibilityManager::OnFullscreenStateChanged(bool is_fullscreen,
1284 aura::Window* root_window) {
1285 if (chromevox_panel_)
1286 chromevox_panel_->UpdateWidgetBounds();
1287}
1288
[email protected]1dfebfc2013-06-04 03:14:321289void AccessibilityManager::SetProfileForTest(Profile* profile) {
1290 SetProfile(profile);
1291}
1292
[email protected]8c79e3f2013-10-30 01:05:141293void AccessibilityManager::SetBrailleControllerForTest(
1294 BrailleController* controller) {
1295 g_braille_controller_for_test = controller;
1296}
1297
[email protected]ce89d9392013-12-11 21:05:201298void AccessibilityManager::EnableSystemSounds(bool system_sounds_enabled) {
1299 system_sounds_enabled_ = system_sounds_enabled;
1300}
1301
1302base::TimeDelta AccessibilityManager::PlayShutdownSound() {
[email protected]4f011f12014-01-15 08:22:451303 if (!system_sounds_enabled_)
[email protected]ce89d9392013-12-11 21:05:201304 return base::TimeDelta();
1305 system_sounds_enabled_ = false;
[email protected]c9eef112014-02-20 19:32:481306 if (!ash::PlaySystemSoundIfSpokenFeedback(SOUND_SHUTDOWN))
[email protected]4f011f12014-01-15 08:22:451307 return base::TimeDelta();
1308 return media::SoundsManager::Get()->GetDuration(SOUND_SHUTDOWN);
[email protected]ce89d9392013-12-11 21:05:201309}
1310
[email protected]f8aa76842014-02-05 19:11:061311void AccessibilityManager::InjectChromeVox(RenderViewHost* render_view_host) {
[email protected]44beb032014-06-11 06:24:371312 LoadChromeVoxExtension(profile_, render_view_host, base::Closure());
[email protected]f8aa76842014-02-05 19:11:061313}
1314
dcheng24002d02016-04-08 02:42:401315std::unique_ptr<AccessibilityStatusSubscription>
1316AccessibilityManager::RegisterCallback(const AccessibilityStatusCallback& cb) {
[email protected]d8edc9c2014-02-25 00:06:031317 return callback_list_.Add(cb);
1318}
1319
1320void AccessibilityManager::NotifyAccessibilityStatusChanged(
1321 AccessibilityStatusEventDetails& details) {
1322 callback_list_.Notify(details);
1323}
1324
[email protected]1dfebfc2013-06-04 03:14:321325void AccessibilityManager::UpdateChromeOSAccessibilityHistograms() {
1326 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSpokenFeedback",
1327 IsSpokenFeedbackEnabled());
1328 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosHighContrast",
1329 IsHighContrastEnabled());
1330 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosVirtualKeyboard",
[email protected]e1b299b2014-01-29 23:53:411331 IsVirtualKeyboardEnabled());
[email protected]7fb7ea42014-02-12 21:19:311332 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosStickyKeys", IsStickyKeysEnabled());
[email protected]1dfebfc2013-06-04 03:14:321333 if (MagnificationManager::Get()) {
avi8a07d53892015-12-24 22:13:531334 uint32_t type = MagnificationManager::Get()->IsMagnifierEnabled()
1335 ? MagnificationManager::Get()->GetMagnifierType()
1336 : 0;
[email protected]1dfebfc2013-06-04 03:14:321337 // '0' means magnifier is disabled.
1338 UMA_HISTOGRAM_ENUMERATION("Accessibility.CrosScreenMagnifier",
1339 type,
pkotwicz0991c822014-10-31 04:21:031340 ui::kMaxMagnifierType + 1);
[email protected]1dfebfc2013-06-04 03:14:321341 }
[email protected]ca3a0a82013-06-18 06:52:121342 if (profile_) {
1343 const PrefService* const prefs = profile_->GetPrefs();
[email protected]ced247a2014-06-13 19:14:191344 UMA_HISTOGRAM_BOOLEAN(
1345 "Accessibility.CrosLargeCursor",
1346 prefs->GetBoolean(prefs::kAccessibilityLargeCursorEnabled));
[email protected]ca3a0a82013-06-18 06:52:121347 UMA_HISTOGRAM_BOOLEAN(
1348 "Accessibility.CrosAlwaysShowA11yMenu",
1349 prefs->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu));
[email protected]0b5a0d2b2013-10-30 03:43:401350
[email protected]ced247a2014-06-13 19:14:191351 bool autoclick_enabled =
1352 prefs->GetBoolean(prefs::kAccessibilityAutoclickEnabled);
[email protected]0b5a0d2b2013-10-30 03:43:401353 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosAutoclick", autoclick_enabled);
1354 if (autoclick_enabled) {
1355 // We only want to log the autoclick delay if the user has actually
1356 // enabled autoclick.
1357 UMA_HISTOGRAM_CUSTOM_TIMES(
1358 "Accessibility.CrosAutoclickDelay",
1359 base::TimeDelta::FromMilliseconds(
[email protected]ced247a2014-06-13 19:14:191360 prefs->GetInteger(prefs::kAccessibilityAutoclickDelayMs)),
[email protected]0b5a0d2b2013-10-30 03:43:401361 base::TimeDelta::FromMilliseconds(1),
1362 base::TimeDelta::FromMilliseconds(3000),
1363 50);
1364 }
[email protected]ca3a0a82013-06-18 06:52:121365 }
dmazzoni756089a22016-03-15 23:55:161366 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCaretHighlight",
1367 IsCaretHighlightEnabled());
1368 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosCursorHighlight",
1369 IsCursorHighlightEnabled());
1370 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosFocusHighlight",
1371 IsFocusHighlightEnabled());
1372 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSelectToSpeak",
1373 IsSelectToSpeakEnabled());
1374 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSwitchAccess",
1375 IsSwitchAccessEnabled());
[email protected]1dfebfc2013-06-04 03:14:321376}
1377
1378void AccessibilityManager::Observe(
1379 int type,
1380 const content::NotificationSource& source,
1381 const content::NotificationDetails& details) {
1382 switch (type) {
[email protected]093d9ba2013-07-23 19:26:211383 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
[email protected]9cf54f362013-07-01 07:28:121384 // Update |profile_| when entering the login screen.
[email protected]c20122572013-12-16 20:35:581385 Profile* profile = ProfileManager::GetActiveUserProfile();
[email protected]d888cdc2013-06-24 17:06:201386 if (ProfileHelper::IsSigninProfile(profile))
1387 SetProfile(profile);
[email protected]1dfebfc2013-06-04 03:14:321388 break;
[email protected]d888cdc2013-06-24 17:06:201389 }
[email protected]e6f20642013-06-11 17:05:461390 case chrome::NOTIFICATION_SESSION_STARTED:
1391 // Update |profile_| when entering a session.
[email protected]c20122572013-12-16 20:35:581392 SetProfile(ProfileManager::GetActiveUserProfile());
[email protected]0e9504d2013-11-05 02:33:291393
1394 // Ensure ChromeVox makes announcements at the start of new sessions.
1395 should_speak_chrome_vox_announcements_on_user_screen_ = true;
[email protected]c20122572013-12-16 20:35:581396
1397 // Add a session state observer to be able to monitor session changes.
1398 if (!session_state_observer_.get() && ash::Shell::HasInstance())
1399 session_state_observer_.reset(
1400 new ash::ScopedSessionStateObserver(this));
[email protected]1dfebfc2013-06-04 03:14:321401 break;
[email protected]1dfebfc2013-06-04 03:14:321402 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
[email protected]e6f20642013-06-11 17:05:461403 // Update |profile_| when exiting a session or shutting down.
1404 Profile* profile = content::Source<Profile>(source).ptr();
1405 if (profile_ == profile)
1406 SetProfile(NULL);
[email protected]1dfebfc2013-06-04 03:14:321407 break;
1408 }
[email protected]b0a2ce32013-07-23 15:24:531409 case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: {
1410 bool is_screen_locked = *content::Details<bool>(details).ptr();
[email protected]9d6c91362013-12-07 21:56:271411 if (spoken_feedback_enabled_) {
[email protected]44beb032014-06-11 06:24:371412 if (is_screen_locked)
1413 LoadChromeVoxToLockScreen(base::Closure());
1414 // If spoken feedback was enabled, make sure it is also enabled on
1415 // the user screen.
1416 // The status tray gets verbalized by user screen ChromeVox, so we need
1417 // to load it on the user screen even if the screen is locked.
1418 LoadChromeVoxToUserScreen(base::Closure());
[email protected]b0a2ce32013-07-23 15:24:531419 }
[email protected]9d6c91362013-12-07 21:56:271420 break;
1421 }
[email protected]1dfebfc2013-06-04 03:14:321422 }
1423}
1424
[email protected]2e5e0b12014-05-07 13:30:201425void AccessibilityManager::OnBrailleDisplayStateChanged(
[email protected]8c79e3f2013-10-30 01:05:141426 const DisplayState& display_state) {
[email protected]a81b2c32014-03-28 06:35:011427 braille_display_connected_ = display_state.available;
[email protected]2e5e0b12014-05-07 13:30:201428 if (braille_display_connected_) {
pkotwicz0991c822014-10-31 04:21:031429 EnableSpokenFeedback(true, ui::A11Y_NOTIFICATION_SHOW);
[email protected]2e5e0b12014-05-07 13:30:201430 }
1431 UpdateBrailleImeState();
[email protected]a81b2c32014-03-28 06:35:011432
1433 AccessibilityStatusEventDetails details(
1434 ACCESSIBILITY_BRAILLE_DISPLAY_CONNECTION_STATE_CHANGED,
1435 braille_display_connected_,
pkotwicz0991c822014-10-31 04:21:031436 ui::A11Y_NOTIFICATION_SHOW);
[email protected]a81b2c32014-03-28 06:35:011437 NotifyAccessibilityStatusChanged(details);
[email protected]8c79e3f2013-10-30 01:05:141438}
[email protected]0e9504d2013-11-05 02:33:291439
[email protected]2e5e0b12014-05-07 13:30:201440void AccessibilityManager::OnBrailleKeyEvent(const KeyEvent& event) {
1441 // Ensure the braille IME is active on braille keyboard (dots) input.
1442 if ((event.command ==
1443 extensions::api::braille_display_private::KEY_COMMAND_DOTS) &&
1444 !braille_ime_current_) {
[email protected]f0881cf2014-08-15 23:31:421445 input_method::InputMethodManager::Get()
1446 ->GetActiveIMEState()
1447 ->ChangeInputMethod(extension_misc::kBrailleImeEngineId,
1448 false /* show_message */);
[email protected]2e5e0b12014-05-07 13:30:201449 }
1450}
1451
dtsengfb6d7cd2016-01-20 23:00:131452void AccessibilityManager::OnExtensionUnloaded(
1453 content::BrowserContext* browser_context,
1454 const extensions::Extension* extension,
1455 extensions::UnloadedExtensionInfo::Reason reason) {
1456 if (extension->id() == keyboard_listener_extension_id_) {
1457 keyboard_listener_extension_id_ = std::string();
1458 keyboard_listener_capture_ = false;
1459 extension_registry_observer_.Remove(
1460 extensions::ExtensionRegistry::Get(browser_context));
1461 }
1462}
1463
1464void AccessibilityManager::OnShutdown(extensions::ExtensionRegistry* registry) {
1465 extension_registry_observer_.Remove(registry);
1466}
1467
[email protected]ee8bbd972014-02-03 06:52:471468void AccessibilityManager::PostLoadChromeVox(Profile* profile) {
1469 // Do any setup work needed immediately after ChromeVox actually loads.
dtsengdcbc97a2015-08-10 20:14:421470 ash::PlaySystemSoundAlways(SOUND_SPOKEN_FEEDBACK_ENABLED);
[email protected]0e9504d2013-11-05 02:33:291471
dtseng703a2042015-01-22 17:46:511472 if (chrome_vox_loaded_on_lock_screen_ ||
1473 should_speak_chrome_vox_announcements_on_user_screen_) {
juncaicf523332015-06-04 00:14:041474 extensions::EventRouter* event_router =
1475 extensions::EventRouter::Get(profile);
1476 CHECK(event_router);
dtseng703a2042015-01-22 17:46:511477
dcheng24002d02016-04-08 02:42:401478 std::unique_ptr<base::ListValue> event_args(new base::ListValue());
1479 std::unique_ptr<extensions::Event> event(new extensions::Event(
Benjamin Kalmanfbf756f2015-06-25 22:56:201480 extensions::events::ACCESSIBILITY_PRIVATE_ON_INTRODUCE_CHROME_VOX,
1481 extensions::api::accessibility_private::OnIntroduceChromeVox::
1482 kEventName,
dcheng7c802f02015-12-31 16:09:551483 std::move(event_args)));
juncaicf523332015-06-04 00:14:041484 event_router->DispatchEventWithLazyListener(
dcheng7c802f02015-12-31 16:09:551485 extension_misc::kChromeVoxExtensionId, std::move(event));
dtseng703a2042015-01-22 17:46:511486 }
[email protected]0e9504d2013-11-05 02:33:291487
[email protected]c9eef112014-02-20 19:32:481488 should_speak_chrome_vox_announcements_on_user_screen_ =
1489 chrome_vox_loaded_on_lock_screen_;
dmazzoni94a4f882015-11-13 05:46:521490
1491 if (!chromevox_panel_) {
1492 chromevox_panel_ = new ChromeVoxPanel(profile_);
1493 chromevox_panel_widget_observer_.reset(
1494 new ChromeVoxPanelWidgetObserver(chromevox_panel_->GetWidget(), this));
1495 }
[email protected]0e9504d2013-11-05 02:33:291496}
1497
[email protected]ee8bbd972014-02-03 06:52:471498void AccessibilityManager::PostUnloadChromeVox(Profile* profile) {
[email protected]9d6c91362013-12-07 21:56:271499 // Do any teardown work needed immediately after ChromeVox actually unloads.
dtsengdcbc97a2015-08-10 20:14:421500 ash::PlaySystemSoundAlways(SOUND_SPOKEN_FEEDBACK_DISABLED);
dmazzonifb33d592014-10-30 19:26:541501 // Clear the accessibility focus ring.
1502 AccessibilityFocusRingController::GetInstance()->SetFocusRing(
1503 std::vector<gfx::Rect>());
[email protected]9d6c91362013-12-07 21:56:271504}
1505
dmazzoni94a4f882015-11-13 05:46:521506void AccessibilityManager::OnChromeVoxPanelClosing() {
1507 aura::Window* root_window = chromevox_panel_->GetRootWindow();
1508 chromevox_panel_widget_observer_.reset(nullptr);
1509 chromevox_panel_ = nullptr;
dmazzoni39d6d4b2016-03-29 22:18:001510
1511 ash::Shelf* shelf = ash::Shelf::ForWindow(root_window);
1512 if (!shelf)
1513 return;
1514
1515 ash::ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager();
1516 if (shelf_layout_manager)
1517 shelf_layout_manager->SetChromeVoxPanelHeight(0);
dmazzoni94a4f882015-11-13 05:46:521518}
1519
1520void AccessibilityManager::OnChromeVoxPanelDestroying() {
1521 chromevox_panel_widget_observer_.reset(nullptr);
1522 chromevox_panel_ = nullptr;
1523}
1524
dtsengfb6d7cd2016-01-20 23:00:131525void AccessibilityManager::SetKeyboardListenerExtensionId(
1526 const std::string& id,
1527 content::BrowserContext* context) {
1528 keyboard_listener_extension_id_ = id;
1529
1530 extensions::ExtensionRegistry* registry =
1531 extensions::ExtensionRegistry::Get(context);
1532 if (!extension_registry_observer_.IsObserving(registry) && !id.empty())
1533 extension_registry_observer_.Add(registry);
1534}
1535
[email protected]1dfebfc2013-06-04 03:14:321536} // namespace chromeos