blob: 98843a500651a5d89050f0269710b90d06dabd7c [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
[email protected]4f011f12014-01-15 08:22:457#include "ash/audio/sounds.h"
[email protected]1c881562013-10-12 07:52:588#include "ash/autoclick/autoclick_controller.h"
[email protected]1dfebfc2013-06-04 03:14:329#include "ash/high_contrast/high_contrast_controller.h"
[email protected]5d2ea362013-12-13 08:10:1810#include "ash/metrics/user_metrics_recorder.h"
[email protected]fdf74bf2014-04-30 21:24:0211#include "ash/session/session_state_delegate.h"
[email protected]1dfebfc2013-06-04 03:14:3212#include "ash/shell.h"
[email protected]08bdabed2013-12-20 07:52:2813#include "ash/sticky_keys/sticky_keys_controller.h"
[email protected]1dfebfc2013-06-04 03:14:3214#include "ash/system/tray/system_tray_notifier.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/memory/singleton.h"
17#include "base/metrics/histogram.h"
[email protected]ab38d192013-12-13 11:38:5818#include "base/path_service.h"
[email protected]1dfebfc2013-06-04 03:14:3219#include "base/prefs/pref_member.h"
20#include "base/prefs/pref_service.h"
[email protected]2e5e0b12014-05-07 13:30:2021#include "base/strings/string_split.h"
22#include "base/strings/string_util.h"
[email protected]0b5a0d2b2013-10-30 03:43:4023#include "base/time/time.h"
[email protected]0aae2fe2013-07-05 07:04:4224#include "base/values.h"
[email protected]1dfebfc2013-06-04 03:14:3225#include "chrome/browser/accessibility/accessibility_extension_api.h"
26#include "chrome/browser/browser_process.h"
[email protected]fdf40f3e2013-07-11 23:55:4627#include "chrome/browser/chrome_notification_types.h"
[email protected]1dfebfc2013-06-04 03:14:3228#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
[email protected]681d0532013-06-11 12:52:5029#include "chrome/browser/chromeos/login/login_display_host.h"
30#include "chrome/browser/chromeos/login/login_display_host_impl.h"
31#include "chrome/browser/chromeos/login/screen_locker.h"
[email protected]5ecf6122013-10-31 12:24:0932#include "chrome/browser/chromeos/login/user_manager.h"
[email protected]681d0532013-06-11 12:52:5033#include "chrome/browser/chromeos/login/webui_login_view.h"
[email protected]e6f20642013-06-11 17:05:4634#include "chrome/browser/chromeos/profiles/profile_helper.h"
[email protected]1dfebfc2013-06-04 03:14:3235#include "chrome/browser/extensions/component_loader.h"
36#include "chrome/browser/extensions/extension_service.h"
[email protected]1dfebfc2013-06-04 03:14:3237#include "chrome/browser/profiles/profile.h"
38#include "chrome/browser/profiles/profile_manager.h"
[email protected]ab38d192013-12-13 11:38:5839#include "chrome/common/chrome_paths.h"
[email protected]9848bf6c2014-05-09 12:34:0040#include "chrome/common/extensions/api/accessibility_private.h"
[email protected]1dfebfc2013-06-04 03:14:3241#include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
42#include "chrome/common/pref_names.h"
[email protected]ce89d9392013-12-11 21:05:2043#include "chromeos/audio/chromeos_sounds.h"
[email protected]2e5e0b12014-05-07 13:30:2044#include "chromeos/ime/input_method_manager.h"
[email protected]0aae2fe2013-07-05 07:04:4245#include "chromeos/login/login_state.h"
[email protected]1dfebfc2013-06-04 03:14:3246#include "content/public/browser/browser_accessibility_state.h"
[email protected]8c79e3f2013-10-30 01:05:1447#include "content/public/browser/browser_thread.h"
[email protected]9cf54f362013-07-01 07:28:1248#include "content/public/browser/notification_details.h"
[email protected]1dfebfc2013-06-04 03:14:3249#include "content/public/browser/notification_service.h"
[email protected]9cf54f362013-07-01 07:28:1250#include "content/public/browser/notification_source.h"
[email protected]1dfebfc2013-06-04 03:14:3251#include "content/public/browser/render_process_host.h"
52#include "content/public/browser/render_view_host.h"
53#include "content/public/browser/web_contents.h"
54#include "content/public/browser/web_ui.h"
[email protected]59b0e602014-01-30 00:41:2455#include "extensions/browser/extension_system.h"
[email protected]1dfebfc2013-06-04 03:14:3256#include "extensions/browser/file_reader.h"
[email protected]e4452d32013-11-15 23:07:4157#include "extensions/common/extension.h"
[email protected]fb820c02014-03-13 15:07:0858#include "extensions/common/extension_messages.h"
[email protected]1dfebfc2013-06-04 03:14:3259#include "extensions/common/extension_resource.h"
60#include "grit/browser_resources.h"
61#include "grit/generated_resources.h"
[email protected]12b0a842013-12-04 20:48:1362#include "media/audio/sounds/sounds_manager.h"
[email protected]1dfebfc2013-06-04 03:14:3263#include "ui/base/l10n/l10n_util.h"
64#include "ui/base/resource/resource_bundle.h"
[email protected]e1b299b2014-01-29 23:53:4165#include "ui/keyboard/keyboard_controller.h"
66#include "ui/keyboard/keyboard_util.h"
[email protected]1dfebfc2013-06-04 03:14:3267
[email protected]8c79e3f2013-10-30 01:05:1468using content::BrowserThread;
[email protected]1dfebfc2013-06-04 03:14:3269using content::RenderViewHost;
[email protected]8c79e3f2013-10-30 01:05:1470using extensions::api::braille_display_private::BrailleController;
71using extensions::api::braille_display_private::DisplayState;
[email protected]2e5e0b12014-05-07 13:30:2072using extensions::api::braille_display_private::KeyEvent;
[email protected]1dfebfc2013-06-04 03:14:3273
74namespace chromeos {
75
76namespace {
77
78static chromeos::AccessibilityManager* g_accessibility_manager = NULL;
79
[email protected]8c79e3f2013-10-30 01:05:1480static BrailleController* g_braille_controller_for_test = NULL;
81
82BrailleController* GetBrailleController() {
83 return g_braille_controller_for_test
84 ? g_braille_controller_for_test
85 : BrailleController::GetInstance();
86}
87
[email protected]ab38d192013-12-13 11:38:5888base::FilePath GetChromeVoxPath() {
89 base::FilePath path;
90 if (!PathService::Get(chrome::DIR_RESOURCES, &path))
91 NOTREACHED();
92 path = path.Append(extension_misc::kChromeVoxExtensionPath);
93 return path;
94}
95
[email protected]1dfebfc2013-06-04 03:14:3296// Helper class that directly loads an extension's content scripts into
97// all of the frames corresponding to a given RenderViewHost.
98class ContentScriptLoader {
99 public:
100 // Initialize the ContentScriptLoader with the ID of the extension
101 // and the RenderViewHost where the scripts should be loaded.
102 ContentScriptLoader(const std::string& extension_id,
103 int render_process_id,
104 int render_view_id)
105 : extension_id_(extension_id),
106 render_process_id_(render_process_id),
107 render_view_id_(render_view_id) {}
108
109 // Call this once with the ExtensionResource corresponding to each
110 // content script to be loaded.
111 void AppendScript(extensions::ExtensionResource resource) {
112 resources_.push(resource);
113 }
114
[email protected]5ecf6122013-10-31 12:24:09115 // Finally, call this method once to fetch all of the resources and
[email protected]1dfebfc2013-06-04 03:14:32116 // load them. This method will delete this object when done.
117 void Run() {
118 if (resources_.empty()) {
119 delete this;
120 return;
121 }
122
123 extensions::ExtensionResource resource = resources_.front();
124 resources_.pop();
125 scoped_refptr<FileReader> reader(new FileReader(resource, base::Bind(
126 &ContentScriptLoader::OnFileLoaded, base::Unretained(this))));
127 reader->Start();
128 }
129
130 private:
131 void OnFileLoaded(bool success, const std::string& data) {
132 if (success) {
133 ExtensionMsg_ExecuteCode_Params params;
134 params.request_id = 0;
135 params.extension_id = extension_id_;
136 params.is_javascript = true;
137 params.code = data;
138 params.run_at = extensions::UserScript::DOCUMENT_IDLE;
139 params.all_frames = true;
140 params.in_main_world = false;
141
142 RenderViewHost* render_view_host =
143 RenderViewHost::FromID(render_process_id_, render_view_id_);
144 if (render_view_host) {
145 render_view_host->Send(new ExtensionMsg_ExecuteCode(
146 render_view_host->GetRoutingID(), params));
147 }
148 }
149 Run();
150 }
151
152 std::string extension_id_;
153 int render_process_id_;
154 int render_view_id_;
155 std::queue<extensions::ExtensionResource> resources_;
156};
157
[email protected]f8aa76842014-02-05 19:11:06158void LoadChromeVoxExtension(Profile* profile,
159 RenderViewHost* render_view_host) {
[email protected]b0a2ce32013-07-23 15:24:53160 ExtensionService* extension_service =
161 extensions::ExtensionSystem::Get(profile)->extension_service();
[email protected]b0a2ce32013-07-23 15:24:53162 std::string extension_id =
[email protected]3e71e48f2014-02-08 01:54:53163 extension_service->component_loader()->AddChromeVoxExtension();
[email protected]f8aa76842014-02-05 19:11:06164 if (render_view_host) {
[email protected]b0a2ce32013-07-23 15:24:53165 ExtensionService* extension_service =
166 extensions::ExtensionSystem::Get(profile)->extension_service();
167 const extensions::Extension* extension =
168 extension_service->extensions()->GetByID(extension_id);
169
[email protected]b0a2ce32013-07-23 15:24:53170 // Set a flag to tell ChromeVox that it's just been enabled,
171 // so that it won't interrupt our speech feedback enabled message.
172 ExtensionMsg_ExecuteCode_Params params;
173 params.request_id = 0;
174 params.extension_id = extension->id();
175 params.is_javascript = true;
176 params.code = "window.INJECTED_AFTER_LOAD = true;";
177 params.run_at = extensions::UserScript::DOCUMENT_IDLE;
178 params.all_frames = true;
179 params.in_main_world = false;
180 render_view_host->Send(new ExtensionMsg_ExecuteCode(
181 render_view_host->GetRoutingID(), params));
182
183 // Inject ChromeVox' content scripts.
184 ContentScriptLoader* loader = new ContentScriptLoader(
185 extension->id(), render_view_host->GetProcess()->GetID(),
186 render_view_host->GetRoutingID());
187
188 const extensions::UserScriptList& content_scripts =
189 extensions::ContentScriptsInfo::GetContentScripts(extension);
190 for (size_t i = 0; i < content_scripts.size(); i++) {
191 const extensions::UserScript& script = content_scripts[i];
192 for (size_t j = 0; j < script.js_scripts().size(); ++j) {
193 const extensions::UserScript::File &file = script.js_scripts()[j];
194 extensions::ExtensionResource resource = extension->GetResource(
195 file.relative_path());
196 loader->AppendScript(resource);
197 }
198 }
199 loader->Run(); // It cleans itself up when done.
200 }
[email protected]b0a2ce32013-07-23 15:24:53201}
202
203void UnloadChromeVoxExtension(Profile* profile) {
[email protected]ab38d192013-12-13 11:38:58204 base::FilePath path = GetChromeVoxPath();
[email protected]b0a2ce32013-07-23 15:24:53205 ExtensionService* extension_service =
206 extensions::ExtensionSystem::Get(profile)->extension_service();
[email protected]b0a2ce32013-07-23 15:24:53207 extension_service->component_loader()->Remove(path);
[email protected]b0a2ce32013-07-23 15:24:53208}
209
[email protected]1dfebfc2013-06-04 03:14:32210} // namespace
211
212///////////////////////////////////////////////////////////////////////////////
213// AccessibilityStatusEventDetails
214
215AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
[email protected]d8edc9c2014-02-25 00:06:03216 AccessibilityNotificationType notification_type,
[email protected]1dfebfc2013-06-04 03:14:32217 bool enabled,
218 ash::AccessibilityNotificationVisibility notify)
[email protected]d8edc9c2014-02-25 00:06:03219 : notification_type(notification_type),
220 enabled(enabled),
[email protected]1dfebfc2013-06-04 03:14:32221 magnifier_type(ash::kDefaultMagnifierType),
222 notify(notify) {}
223
224AccessibilityStatusEventDetails::AccessibilityStatusEventDetails(
[email protected]d8edc9c2014-02-25 00:06:03225 AccessibilityNotificationType notification_type,
[email protected]1dfebfc2013-06-04 03:14:32226 bool enabled,
227 ash::MagnifierType magnifier_type,
228 ash::AccessibilityNotificationVisibility notify)
[email protected]d8edc9c2014-02-25 00:06:03229 : notification_type(notification_type),
230 enabled(enabled),
[email protected]1dfebfc2013-06-04 03:14:32231 magnifier_type(magnifier_type),
232 notify(notify) {}
233
234///////////////////////////////////////////////////////////////////////////////
235//
[email protected]0aae2fe2013-07-05 07:04:42236// AccessibilityManager::PrefHandler
237
238AccessibilityManager::PrefHandler::PrefHandler(const char* pref_path)
239 : pref_path_(pref_path) {}
240
241AccessibilityManager::PrefHandler::~PrefHandler() {}
242
243void AccessibilityManager::PrefHandler::HandleProfileChanged(
244 Profile* previous_profile, Profile* current_profile) {
245 // Returns if the current profile is null.
246 if (!current_profile)
247 return;
248
249 // If the user set a pref value on the login screen and is now starting a
250 // session with a new profile, copy the pref value to the profile.
251 if ((previous_profile &&
252 ProfileHelper::IsSigninProfile(previous_profile) &&
253 current_profile->IsNewProfile() &&
254 !ProfileHelper::IsSigninProfile(current_profile)) ||
255 // Special case for Guest mode:
256 // Guest mode launches a guest-mode browser process before session starts,
257 // so the previous profile is null.
258 (!previous_profile &&
259 current_profile->IsGuestSession())) {
260 // Returns if the pref has not been set by the user.
261 const PrefService::Preference* pref = ProfileHelper::GetSigninProfile()->
262 GetPrefs()->FindPreference(pref_path_);
263 if (!pref || !pref->IsUserControlled())
264 return;
265
266 // Copy the pref value from the signin screen.
267 const base::Value* value_on_login = pref->GetValue();
268 PrefService* user_prefs = current_profile->GetPrefs();
269 user_prefs->Set(pref_path_, *value_on_login);
270 }
271}
272
273///////////////////////////////////////////////////////////////////////////////
274//
[email protected]1dfebfc2013-06-04 03:14:32275// AccessibilityManager
276
277// static
278void AccessibilityManager::Initialize() {
279 CHECK(g_accessibility_manager == NULL);
280 g_accessibility_manager = new AccessibilityManager();
281}
282
283// static
284void AccessibilityManager::Shutdown() {
285 CHECK(g_accessibility_manager);
286 delete g_accessibility_manager;
287 g_accessibility_manager = NULL;
288}
289
290// static
291AccessibilityManager* AccessibilityManager::Get() {
292 return g_accessibility_manager;
293}
294
[email protected]d80f19302013-06-07 13:12:14295AccessibilityManager::AccessibilityManager()
296 : profile_(NULL),
[email protected]b0a2ce32013-07-23 15:24:53297 chrome_vox_loaded_on_lock_screen_(false),
298 chrome_vox_loaded_on_user_screen_(false),
[email protected]0aae2fe2013-07-05 07:04:42299 large_cursor_pref_handler_(prefs::kLargeCursorEnabled),
300 spoken_feedback_pref_handler_(prefs::kSpokenFeedbackEnabled),
301 high_contrast_pref_handler_(prefs::kHighContrastEnabled),
[email protected]1c881562013-10-12 07:52:58302 autoclick_pref_handler_(prefs::kAutoclickEnabled),
[email protected]84d652d2013-10-23 13:57:57303 autoclick_delay_pref_handler_(prefs::kAutoclickDelayMs),
[email protected]e1b299b2014-01-29 23:53:41304 virtual_keyboard_pref_handler_(prefs::kVirtualKeyboardEnabled),
[email protected]d80f19302013-06-07 13:12:14305 large_cursor_enabled_(false),
[email protected]93a534e2013-06-20 16:41:44306 sticky_keys_enabled_(false),
[email protected]d80f19302013-06-07 13:12:14307 spoken_feedback_enabled_(false),
308 high_contrast_enabled_(false),
[email protected]186ba06bc2013-11-26 18:02:19309 autoclick_enabled_(false),
[email protected]84d652d2013-10-23 13:57:57310 autoclick_delay_ms_(ash::AutoclickController::kDefaultAutoclickDelayMs),
[email protected]e1b299b2014-01-29 23:53:41311 virtual_keyboard_enabled_(false),
[email protected]8c79e3f2013-10-30 01:05:14312 spoken_feedback_notification_(ash::A11Y_NOTIFICATION_NONE),
[email protected]0e9504d2013-11-05 02:33:29313 weak_ptr_factory_(this),
[email protected]ce89d9392013-12-11 21:05:20314 should_speak_chrome_vox_announcements_on_user_screen_(true),
[email protected]a81b2c32014-03-28 06:35:01315 system_sounds_enabled_(false),
316 braille_display_connected_(false),
[email protected]2e5e0b12014-05-07 13:30:20317 scoped_braille_observer_(this),
318 braille_ime_current_(false) {
[email protected]1dfebfc2013-06-04 03:14:32319 notification_registrar_.Add(this,
[email protected]093d9ba2013-07-23 19:26:21320 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
[email protected]e6f20642013-06-11 17:05:46321 content::NotificationService::AllSources());
322 notification_registrar_.Add(this,
[email protected]1dfebfc2013-06-04 03:14:32323 chrome::NOTIFICATION_SESSION_STARTED,
324 content::NotificationService::AllSources());
325 notification_registrar_.Add(this,
[email protected]1dfebfc2013-06-04 03:14:32326 chrome::NOTIFICATION_PROFILE_DESTROYED,
327 content::NotificationService::AllSources());
[email protected]b0a2ce32013-07-23 15:24:53328 notification_registrar_.Add(this,
329 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
330 content::NotificationService::AllSources());
[email protected]c20122572013-12-16 20:35:58331
[email protected]1488a035f2014-03-28 21:12:07332 input_method::InputMethodManager::Get()->AddObserver(this);
333
[email protected]12b0a842013-12-04 20:48:13334 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
[email protected]ce89d9392013-12-11 21:05:20335 media::SoundsManager* manager = media::SoundsManager::Get();
336 manager->Initialize(SOUND_SHUTDOWN,
337 bundle.GetRawDataResource(IDR_SOUND_SHUTDOWN_WAV));
338 manager->Initialize(
339 SOUND_SPOKEN_FEEDBACK_ENABLED,
340 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_ENABLED_WAV));
341 manager->Initialize(
342 SOUND_SPOKEN_FEEDBACK_DISABLED,
343 bundle.GetRawDataResource(IDR_SOUND_SPOKEN_FEEDBACK_DISABLED_WAV));
[email protected]1dfebfc2013-06-04 03:14:32344}
345
346AccessibilityManager::~AccessibilityManager() {
347 CHECK(this == g_accessibility_manager);
[email protected]d8edc9c2014-02-25 00:06:03348 AccessibilityStatusEventDetails details(
349 ACCESSIBILITY_MANAGER_SHUTDOWN,
350 false,
351 ash::A11Y_NOTIFICATION_NONE);
352 NotifyAccessibilityStatusChanged(details);
[email protected]1488a035f2014-03-28 21:12:07353 input_method::InputMethodManager::Get()->RemoveObserver(this);
[email protected]1dfebfc2013-06-04 03:14:32354}
355
[email protected]c20122572013-12-16 20:35:58356bool AccessibilityManager::ShouldShowAccessibilityMenu() {
357 // If any of the loaded profiles has an accessibility feature turned on - or
358 // enforced to always show the menu - we return true to show the menu.
359 std::vector<Profile*> profiles =
360 g_browser_process->profile_manager()->GetLoadedProfiles();
361 for (std::vector<Profile*>::iterator it = profiles.begin();
362 it != profiles.end();
363 ++it) {
364 PrefService* pref_service = (*it)->GetPrefs();
365 if (pref_service->GetBoolean(prefs::kStickyKeysEnabled) ||
366 pref_service->GetBoolean(prefs::kLargeCursorEnabled) ||
367 pref_service->GetBoolean(prefs::kSpokenFeedbackEnabled) ||
368 pref_service->GetBoolean(prefs::kHighContrastEnabled) ||
369 pref_service->GetBoolean(prefs::kAutoclickEnabled) ||
370 pref_service->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu) ||
[email protected]e1b299b2014-01-29 23:53:41371 pref_service->GetBoolean(prefs::kScreenMagnifierEnabled) ||
372 pref_service->GetBoolean(prefs::kVirtualKeyboardEnabled))
[email protected]c20122572013-12-16 20:35:58373 return true;
374 }
375 return false;
376}
377
[email protected]a4994f1e2014-02-11 18:58:16378bool AccessibilityManager::ShouldEnableCursorCompositing() {
[email protected]f74c0b9c2014-04-17 23:24:03379#if defined(OS_CHROMEOS)
380 if (!profile_)
381 return false;
382 PrefService* pref_service = profile_->GetPrefs();
383 // Enable cursor compositing when one or more of the listed accessibility
384 // features are turned on.
385 if (pref_service->GetBoolean(prefs::kLargeCursorEnabled) ||
386 pref_service->GetBoolean(prefs::kHighContrastEnabled) ||
387 pref_service->GetBoolean(prefs::kScreenMagnifierEnabled))
388 return true;
389#endif
[email protected]a4994f1e2014-02-11 18:58:16390 return false;
391}
392
[email protected]8126b812013-06-06 03:49:17393void AccessibilityManager::EnableLargeCursor(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14394 if (!profile_)
395 return;
396
397 PrefService* pref_service = profile_->GetPrefs();
398 pref_service->SetBoolean(prefs::kLargeCursorEnabled, enabled);
399 pref_service->CommitPendingWrite();
400}
401
402void AccessibilityManager::UpdateLargeCursorFromPref() {
403 if (!profile_)
404 return;
405
406 const bool enabled =
407 profile_->GetPrefs()->GetBoolean(prefs::kLargeCursorEnabled);
408
[email protected]8126b812013-06-06 03:49:17409 if (large_cursor_enabled_ == enabled)
410 return;
411
412 large_cursor_enabled_ = enabled;
413
[email protected]d8edc9c2014-02-25 00:06:03414 AccessibilityStatusEventDetails details(
415 ACCESSIBILITY_TOGGLE_LARGE_CURSOR,
416 enabled,
417 ash::A11Y_NOTIFICATION_NONE);
418
419 NotifyAccessibilityStatusChanged(details);
[email protected]846be6e2013-06-07 08:03:26420
[email protected]8126b812013-06-06 03:49:17421#if defined(USE_ASH)
422 // Large cursor is implemented only in ash.
[email protected]a7c93e32013-09-03 08:50:30423 ash::Shell::GetInstance()->cursor_manager()->SetCursorSet(
424 enabled ? ui::CURSOR_SET_LARGE : ui::CURSOR_SET_NORMAL);
[email protected]8126b812013-06-06 03:49:17425#endif
[email protected]87ec2202014-02-06 06:24:27426
427#if defined(OS_CHROMEOS)
[email protected]87ec2202014-02-06 06:24:27428 ash::Shell::GetInstance()->SetCursorCompositingEnabled(
[email protected]a4994f1e2014-02-11 18:58:16429 ShouldEnableCursorCompositing());
[email protected]87ec2202014-02-06 06:24:27430#endif
[email protected]8126b812013-06-06 03:49:17431}
432
[email protected]5ecf6122013-10-31 12:24:09433bool AccessibilityManager::IsIncognitoAllowed() {
434 UserManager* user_manager = UserManager::Get();
435 // Supervised users can't create incognito-mode windows.
436 return !(user_manager->IsLoggedInAsLocallyManagedUser());
437}
438
[email protected]8126b812013-06-06 03:49:17439bool AccessibilityManager::IsLargeCursorEnabled() {
440 return large_cursor_enabled_;
441}
442
[email protected]93a534e2013-06-20 16:41:44443void AccessibilityManager::EnableStickyKeys(bool enabled) {
444 if (!profile_)
445 return;
446 PrefService* pref_service = profile_->GetPrefs();
447 pref_service->SetBoolean(prefs::kStickyKeysEnabled, enabled);
448 pref_service->CommitPendingWrite();
449}
450
451bool AccessibilityManager::IsStickyKeysEnabled() {
452 return sticky_keys_enabled_;
453}
454
455void AccessibilityManager::UpdateStickyKeysFromPref() {
456 if (!profile_)
457 return;
458
459 const bool enabled =
460 profile_->GetPrefs()->GetBoolean(prefs::kStickyKeysEnabled);
461
462 if (sticky_keys_enabled_ == enabled)
463 return;
464
465 sticky_keys_enabled_ = enabled;
466#if defined(USE_ASH)
467 // Sticky keys is implemented only in ash.
[email protected]08bdabed2013-12-20 07:52:28468 ash::Shell::GetInstance()->sticky_keys_controller()->Enable(enabled);
[email protected]93a534e2013-06-20 16:41:44469#endif
470}
471
[email protected]1dfebfc2013-06-04 03:14:32472void AccessibilityManager::EnableSpokenFeedback(
473 bool enabled,
[email protected]1dfebfc2013-06-04 03:14:32474 ash::AccessibilityNotificationVisibility notify) {
[email protected]1dfebfc2013-06-04 03:14:32475 if (!profile_)
476 return;
477
[email protected]5d2ea362013-12-13 08:10:18478 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(
479 enabled ? ash::UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK
480 : ash::UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK);
481
[email protected]d80f19302013-06-07 13:12:14482 spoken_feedback_notification_ = notify;
483
[email protected]1dfebfc2013-06-04 03:14:32484 PrefService* pref_service = profile_->GetPrefs();
485 pref_service->SetBoolean(
486 prefs::kSpokenFeedbackEnabled, enabled);
487 pref_service->CommitPendingWrite();
[email protected]d80f19302013-06-07 13:12:14488
[email protected]d80f19302013-06-07 13:12:14489 spoken_feedback_notification_ = ash::A11Y_NOTIFICATION_NONE;
490}
491
492void AccessibilityManager::UpdateSpokenFeedbackFromPref() {
493 if (!profile_)
494 return;
495
496 const bool enabled =
497 profile_->GetPrefs()->GetBoolean(prefs::kSpokenFeedbackEnabled);
498
499 if (spoken_feedback_enabled_ == enabled)
500 return;
501
502 spoken_feedback_enabled_ = enabled;
503
[email protected]1dfebfc2013-06-04 03:14:32504 ExtensionAccessibilityEventRouter::GetInstance()->
505 SetAccessibilityEnabled(enabled);
506
[email protected]d8edc9c2014-02-25 00:06:03507 AccessibilityStatusEventDetails details(
508 ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK,
509 enabled,
510 spoken_feedback_notification_);
511
512 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32513
[email protected]0e9504d2013-11-05 02:33:29514 if (enabled) {
[email protected]b0a2ce32013-07-23 15:24:53515 LoadChromeVox();
[email protected]0e9504d2013-11-05 02:33:29516 } else {
[email protected]ee8bbd972014-02-03 06:52:47517 UnloadChromeVox();
[email protected]0e9504d2013-11-05 02:33:29518 }
[email protected]2e5e0b12014-05-07 13:30:20519 UpdateBrailleImeState();
[email protected]b0a2ce32013-07-23 15:24:53520}
521
522void AccessibilityManager::LoadChromeVox() {
523 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker();
524 if (screen_locker && screen_locker->locked()) {
525 // If on the lock screen, loads ChromeVox only to the lock screen as for
526 // now. On unlock, it will be loaded to the user screen.
527 // (see. AccessibilityManager::Observe())
528 LoadChromeVoxToLockScreen();
[email protected]ee8bbd972014-02-03 06:52:47529 } else {
530 LoadChromeVoxToUserScreen();
[email protected]b0a2ce32013-07-23 15:24:53531 }
[email protected]ee8bbd972014-02-03 06:52:47532 PostLoadChromeVox(profile_);
[email protected]b0a2ce32013-07-23 15:24:53533}
534
535void AccessibilityManager::LoadChromeVoxToUserScreen() {
536 if (chrome_vox_loaded_on_user_screen_)
537 return;
538
539 // Determine whether an OOBE screen is currently being shown. If so,
540 // ChromeVox will be injected directly into that screen.
[email protected]681d0532013-06-11 12:52:50541 content::WebUI* login_web_ui = NULL;
[email protected]681d0532013-06-11 12:52:50542
[email protected]b0a2ce32013-07-23 15:24:53543 if (ProfileHelper::IsSigninProfile(profile_)) {
544 LoginDisplayHost* login_display_host = LoginDisplayHostImpl::default_host();
545 if (login_display_host) {
546 WebUILoginView* web_ui_login_view =
547 login_display_host->GetWebUILoginView();
548 if (web_ui_login_view)
549 login_web_ui = web_ui_login_view->GetWebUI();
[email protected]1dfebfc2013-06-04 03:14:32550 }
[email protected]a4846a02014-04-21 19:11:45551
552 // Lock screen uses the signin progile.
553 chrome_vox_loaded_on_lock_screen_ = true;
[email protected]1dfebfc2013-06-04 03:14:32554 }
[email protected]b0a2ce32013-07-23 15:24:53555
[email protected]f8aa76842014-02-05 19:11:06556 LoadChromeVoxExtension(profile_, login_web_ui ?
557 login_web_ui->GetWebContents()->GetRenderViewHost() : NULL);
[email protected]b0a2ce32013-07-23 15:24:53558 chrome_vox_loaded_on_user_screen_ = true;
559}
560
561void AccessibilityManager::LoadChromeVoxToLockScreen() {
562 if (chrome_vox_loaded_on_lock_screen_)
563 return;
564
565 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker();
566 if (screen_locker && screen_locker->locked()) {
567 content::WebUI* lock_web_ui = screen_locker->GetAssociatedWebUI();
568 if (lock_web_ui) {
569 Profile* profile = Profile::FromWebUI(lock_web_ui);
[email protected]f8aa76842014-02-05 19:11:06570 LoadChromeVoxExtension(profile,
571 lock_web_ui->GetWebContents()->GetRenderViewHost());
[email protected]b0a2ce32013-07-23 15:24:53572 chrome_vox_loaded_on_lock_screen_ = true;
573 }
574 }
575}
576
577void AccessibilityManager::UnloadChromeVox() {
578 if (chrome_vox_loaded_on_lock_screen_)
579 UnloadChromeVoxFromLockScreen();
580
581 if (chrome_vox_loaded_on_user_screen_) {
582 UnloadChromeVoxExtension(profile_);
583 chrome_vox_loaded_on_user_screen_ = false;
584 }
[email protected]ee8bbd972014-02-03 06:52:47585
586 PostUnloadChromeVox(profile_);
[email protected]b0a2ce32013-07-23 15:24:53587}
588
589void AccessibilityManager::UnloadChromeVoxFromLockScreen() {
590 // Lock screen uses the signin progile.
591 Profile* signin_profile = ProfileHelper::GetSigninProfile();
592 UnloadChromeVoxExtension(signin_profile);
593 chrome_vox_loaded_on_lock_screen_ = false;
[email protected]1dfebfc2013-06-04 03:14:32594}
595
596bool AccessibilityManager::IsSpokenFeedbackEnabled() {
597 return spoken_feedback_enabled_;
598}
599
600void AccessibilityManager::ToggleSpokenFeedback(
[email protected]1dfebfc2013-06-04 03:14:32601 ash::AccessibilityNotificationVisibility notify) {
[email protected]681d0532013-06-11 12:52:50602 EnableSpokenFeedback(!IsSpokenFeedbackEnabled(), notify);
[email protected]1dfebfc2013-06-04 03:14:32603}
604
[email protected]1dfebfc2013-06-04 03:14:32605void AccessibilityManager::EnableHighContrast(bool enabled) {
[email protected]d80f19302013-06-07 13:12:14606 if (!profile_)
607 return;
608
609 PrefService* pref_service = profile_->GetPrefs();
610 pref_service->SetBoolean(prefs::kHighContrastEnabled, enabled);
611 pref_service->CommitPendingWrite();
612}
613
614void AccessibilityManager::UpdateHighContrastFromPref() {
615 if (!profile_)
616 return;
617
618 const bool enabled =
619 profile_->GetPrefs()->GetBoolean(prefs::kHighContrastEnabled);
620
[email protected]1dfebfc2013-06-04 03:14:32621 if (high_contrast_enabled_ == enabled)
622 return;
623
624 high_contrast_enabled_ = enabled;
625
[email protected]d8edc9c2014-02-25 00:06:03626 AccessibilityStatusEventDetails details(
627 ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE,
628 enabled,
629 ash::A11Y_NOTIFICATION_NONE);
630
631 NotifyAccessibilityStatusChanged(details);
[email protected]1dfebfc2013-06-04 03:14:32632
633#if defined(USE_ASH)
634 ash::Shell::GetInstance()->high_contrast_controller()->SetEnabled(enabled);
635#endif
[email protected]87ec2202014-02-06 06:24:27636
637#if defined(OS_CHROMEOS)
[email protected]87ec2202014-02-06 06:24:27638 ash::Shell::GetInstance()->SetCursorCompositingEnabled(
[email protected]a4994f1e2014-02-11 18:58:16639 ShouldEnableCursorCompositing());
[email protected]87ec2202014-02-06 06:24:27640#endif
[email protected]1dfebfc2013-06-04 03:14:32641}
642
[email protected]628b8902014-03-12 05:26:41643void AccessibilityManager::OnLocaleChanged() {
[email protected]d1d5f4f2013-06-14 07:17:09644 if (!profile_)
645 return;
646
647 if (!IsSpokenFeedbackEnabled())
648 return;
649
650 // If the system locale changes and spoken feedback is enabled,
651 // reload ChromeVox so that it switches its internal translations
652 // to the new language.
653 EnableSpokenFeedback(false, ash::A11Y_NOTIFICATION_NONE);
654 EnableSpokenFeedback(true, ash::A11Y_NOTIFICATION_NONE);
655}
656
[email protected]1dfebfc2013-06-04 03:14:32657bool AccessibilityManager::IsHighContrastEnabled() {
658 return high_contrast_enabled_;
659}
660
[email protected]1c881562013-10-12 07:52:58661void AccessibilityManager::EnableAutoclick(bool enabled) {
662 if (!profile_)
663 return;
664
665 PrefService* pref_service = profile_->GetPrefs();
666 pref_service->SetBoolean(prefs::kAutoclickEnabled, enabled);
667 pref_service->CommitPendingWrite();
668}
669
670bool AccessibilityManager::IsAutoclickEnabled() {
671 return autoclick_enabled_;
672}
673
674void AccessibilityManager::UpdateAutoclickFromPref() {
675 bool enabled =
676 profile_->GetPrefs()->GetBoolean(prefs::kAutoclickEnabled);
677
678 if (autoclick_enabled_ == enabled)
679 return;
680 autoclick_enabled_ = enabled;
681
682#if defined(USE_ASH)
683 ash::Shell::GetInstance()->autoclick_controller()->SetEnabled(enabled);
684#endif
685}
686
[email protected]84d652d2013-10-23 13:57:57687void AccessibilityManager::SetAutoclickDelay(int delay_ms) {
688 if (!profile_)
689 return;
690
691 PrefService* pref_service = profile_->GetPrefs();
692 pref_service->SetInteger(prefs::kAutoclickDelayMs, delay_ms);
693 pref_service->CommitPendingWrite();
694}
695
696int AccessibilityManager::GetAutoclickDelay() const {
697 return autoclick_delay_ms_;
698}
699
700void AccessibilityManager::UpdateAutoclickDelayFromPref() {
701 int autoclick_delay_ms =
702 profile_->GetPrefs()->GetInteger(prefs::kAutoclickDelayMs);
703
704 if (autoclick_delay_ms == autoclick_delay_ms_)
705 return;
706 autoclick_delay_ms_ = autoclick_delay_ms;
707
708#if defined(USE_ASH)
709 ash::Shell::GetInstance()->autoclick_controller()->SetAutoclickDelay(
710 autoclick_delay_ms_);
711#endif
712}
713
[email protected]e1b299b2014-01-29 23:53:41714void AccessibilityManager::EnableVirtualKeyboard(bool enabled) {
715 if (!profile_)
716 return;
717
718 PrefService* pref_service = profile_->GetPrefs();
719 pref_service->SetBoolean(prefs::kVirtualKeyboardEnabled, enabled);
720 pref_service->CommitPendingWrite();
721}
722
723bool AccessibilityManager::IsVirtualKeyboardEnabled() {
724 return virtual_keyboard_enabled_;
725}
726
727void AccessibilityManager::UpdateVirtualKeyboardFromPref() {
728 if (!profile_)
729 return;
730
731 const bool enabled =
732 profile_->GetPrefs()->GetBoolean(prefs::kVirtualKeyboardEnabled);
733
734 if (virtual_keyboard_enabled_ == enabled)
735 return;
736 virtual_keyboard_enabled_ = enabled;
737
[email protected]d8edc9c2014-02-25 00:06:03738 AccessibilityStatusEventDetails details(
739 ACCESSIBILITY_TOGGLE_VIRTUAL_KEYBOARD,
740 enabled,
741 ash::A11Y_NOTIFICATION_NONE);
742
743 NotifyAccessibilityStatusChanged(details);
[email protected]e1b299b2014-01-29 23:53:41744
745#if defined(USE_ASH)
746 keyboard::SetAccessibilityKeyboardEnabled(enabled);
[email protected]ff0eb112014-05-07 13:31:35747 // Note that there are two versions of the on-screen keyboard. A full layout
748 // is provided for accessibility, which includes sticky modifier keys to
749 // enable typing of hotkeys. A compact version is used in touchview mode
750 // to provide a layout with larger keys to facilitate touch typing. In the
751 // event that the a11y keyboard is being disabled, an on-screen keyboard might
752 // still be enabled and a forced reset is required to pick up the layout
753 // change.
754 if (keyboard::IsKeyboardEnabled())
[email protected]e1b299b2014-01-29 23:53:41755 ash::Shell::GetInstance()->CreateKeyboard();
[email protected]ff0eb112014-05-07 13:31:35756 else
[email protected]e1b299b2014-01-29 23:53:41757 ash::Shell::GetInstance()->DeactivateKeyboard();
758#endif
759}
760
[email protected]a81b2c32014-03-28 06:35:01761bool AccessibilityManager::IsBrailleDisplayConnected() const {
762 return braille_display_connected_;
763}
764
[email protected]8c79e3f2013-10-30 01:05:14765void AccessibilityManager::CheckBrailleState() {
[email protected]a81b2c32014-03-28 06:35:01766 BrailleController* braille_controller = GetBrailleController();
767 if (!scoped_braille_observer_.IsObserving(braille_controller))
768 scoped_braille_observer_.Add(braille_controller);
[email protected]8c79e3f2013-10-30 01:05:14769 BrowserThread::PostTaskAndReplyWithResult(
[email protected]a81b2c32014-03-28 06:35:01770 BrowserThread::IO,
771 FROM_HERE,
772 base::Bind(&BrailleController::GetDisplayState,
773 base::Unretained(braille_controller)),
[email protected]8c79e3f2013-10-30 01:05:14774 base::Bind(&AccessibilityManager::ReceiveBrailleDisplayState,
775 weak_ptr_factory_.GetWeakPtr()));
776}
777
778void AccessibilityManager::ReceiveBrailleDisplayState(
779 scoped_ptr<extensions::api::braille_display_private::DisplayState> state) {
[email protected]2e5e0b12014-05-07 13:30:20780 OnBrailleDisplayStateChanged(*state);
781}
782
783void AccessibilityManager::UpdateBrailleImeState() {
784 if (!profile_)
785 return;
786 PrefService* pref_service = profile_->GetPrefs();
787 std::vector<std::string> preload_engines;
788 base::SplitString(pref_service->GetString(prefs::kLanguagePreloadEngines),
789 ',',
790 &preload_engines);
791 std::vector<std::string>::iterator it =
792 std::find(preload_engines.begin(),
793 preload_engines.end(),
794 extension_misc::kBrailleImeEngineId);
795 bool is_enabled = (it != preload_engines.end());
796 bool should_be_enabled =
797 (spoken_feedback_enabled_ && braille_display_connected_);
798 if (is_enabled == should_be_enabled)
799 return;
800 if (should_be_enabled)
801 preload_engines.push_back(extension_misc::kBrailleImeEngineId);
802 else
803 preload_engines.erase(it);
804 pref_service->SetString(prefs::kLanguagePreloadEngines,
805 JoinString(preload_engines, ','));
806 braille_ime_current_ = false;
[email protected]8c79e3f2013-10-30 01:05:14807}
808
[email protected]1488a035f2014-03-28 21:12:07809// Overridden from InputMethodManager::Observer.
810void AccessibilityManager::InputMethodChanged(
811 input_method::InputMethodManager* manager,
812 bool show_message) {
813#if defined(USE_ASH)
814 // Sticky keys is implemented only in ash.
815 ash::Shell::GetInstance()->sticky_keys_controller()->SetModifiersEnabled(
816 manager->IsISOLevel5ShiftUsedByCurrentInputMethod(),
817 manager->IsAltGrUsedByCurrentInputMethod());
818#endif
[email protected]2e5e0b12014-05-07 13:30:20819 const chromeos::input_method::InputMethodDescriptor descriptor =
820 manager->GetCurrentInputMethod();
821 braille_ime_current_ =
822 (descriptor.id() == extension_misc::kBrailleImeEngineId);
[email protected]1488a035f2014-03-28 21:12:07823}
[email protected]8c79e3f2013-10-30 01:05:14824
[email protected]1dfebfc2013-06-04 03:14:32825void AccessibilityManager::SetProfile(Profile* profile) {
826 pref_change_registrar_.reset();
[email protected]d1d5f4f2013-06-14 07:17:09827 local_state_pref_change_registrar_.reset();
[email protected]1dfebfc2013-06-04 03:14:32828
829 if (profile) {
[email protected]0aae2fe2013-07-05 07:04:42830 // TODO(yoshiki): Move following code to PrefHandler.
[email protected]1dfebfc2013-06-04 03:14:32831 pref_change_registrar_.reset(new PrefChangeRegistrar);
832 pref_change_registrar_->Init(profile->GetPrefs());
833 pref_change_registrar_->Add(
[email protected]8126b812013-06-06 03:49:17834 prefs::kLargeCursorEnabled,
[email protected]d80f19302013-06-07 13:12:14835 base::Bind(&AccessibilityManager::UpdateLargeCursorFromPref,
[email protected]8126b812013-06-06 03:49:17836 base::Unretained(this)));
837 pref_change_registrar_->Add(
[email protected]93a534e2013-06-20 16:41:44838 prefs::kStickyKeysEnabled,
839 base::Bind(&AccessibilityManager::UpdateStickyKeysFromPref,
840 base::Unretained(this)));
841 pref_change_registrar_->Add(
[email protected]1dfebfc2013-06-04 03:14:32842 prefs::kSpokenFeedbackEnabled,
[email protected]d80f19302013-06-07 13:12:14843 base::Bind(&AccessibilityManager::UpdateSpokenFeedbackFromPref,
[email protected]1dfebfc2013-06-04 03:14:32844 base::Unretained(this)));
845 pref_change_registrar_->Add(
846 prefs::kHighContrastEnabled,
[email protected]d80f19302013-06-07 13:12:14847 base::Bind(&AccessibilityManager::UpdateHighContrastFromPref,
[email protected]1dfebfc2013-06-04 03:14:32848 base::Unretained(this)));
[email protected]1c881562013-10-12 07:52:58849 pref_change_registrar_->Add(
850 prefs::kAutoclickEnabled,
851 base::Bind(&AccessibilityManager::UpdateAutoclickFromPref,
852 base::Unretained(this)));
[email protected]84d652d2013-10-23 13:57:57853 pref_change_registrar_->Add(
854 prefs::kAutoclickDelayMs,
855 base::Bind(&AccessibilityManager::UpdateAutoclickDelayFromPref,
856 base::Unretained(this)));
[email protected]e1b299b2014-01-29 23:53:41857 pref_change_registrar_->Add(
858 prefs::kVirtualKeyboardEnabled,
859 base::Bind(&AccessibilityManager::UpdateVirtualKeyboardFromPref,
860 base::Unretained(this)));
[email protected]1dfebfc2013-06-04 03:14:32861
[email protected]d1d5f4f2013-06-14 07:17:09862 local_state_pref_change_registrar_.reset(new PrefChangeRegistrar);
863 local_state_pref_change_registrar_->Init(g_browser_process->local_state());
864 local_state_pref_change_registrar_->Add(
865 prefs::kApplicationLocale,
[email protected]628b8902014-03-12 05:26:41866 base::Bind(&AccessibilityManager::OnLocaleChanged,
[email protected]d1d5f4f2013-06-14 07:17:09867 base::Unretained(this)));
868
[email protected]1dfebfc2013-06-04 03:14:32869 content::BrowserAccessibilityState::GetInstance()->AddHistogramCallback(
870 base::Bind(
871 &AccessibilityManager::UpdateChromeOSAccessibilityHistograms,
872 base::Unretained(this)));
873 }
874
[email protected]0aae2fe2013-07-05 07:04:42875 large_cursor_pref_handler_.HandleProfileChanged(profile_, profile);
876 spoken_feedback_pref_handler_.HandleProfileChanged(profile_, profile);
877 high_contrast_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]1c881562013-10-12 07:52:58878 autoclick_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]84d652d2013-10-23 13:57:57879 autoclick_delay_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]42b471f2014-01-31 20:31:29880 virtual_keyboard_pref_handler_.HandleProfileChanged(profile_, profile);
[email protected]0aae2fe2013-07-05 07:04:42881
[email protected]a81b2c32014-03-28 06:35:01882 bool had_profile = (profile_ != NULL);
883 profile_ = profile;
884
885 if (!had_profile && profile)
[email protected]8c79e3f2013-10-30 01:05:14886 CheckBrailleState();
[email protected]2e5e0b12014-05-07 13:30:20887 else
888 UpdateBrailleImeState();
[email protected]d80f19302013-06-07 13:12:14889 UpdateLargeCursorFromPref();
[email protected]93a534e2013-06-20 16:41:44890 UpdateStickyKeysFromPref();
[email protected]d80f19302013-06-07 13:12:14891 UpdateSpokenFeedbackFromPref();
892 UpdateHighContrastFromPref();
[email protected]1c881562013-10-12 07:52:58893 UpdateAutoclickFromPref();
[email protected]84d652d2013-10-23 13:57:57894 UpdateAutoclickDelayFromPref();
[email protected]e1b299b2014-01-29 23:53:41895 UpdateVirtualKeyboardFromPref();
[email protected]1dfebfc2013-06-04 03:14:32896}
897
[email protected]c20122572013-12-16 20:35:58898void AccessibilityManager::ActiveUserChanged(const std::string& user_id) {
899 SetProfile(ProfileManager::GetActiveUserProfile());
900}
901
[email protected]1dfebfc2013-06-04 03:14:32902void AccessibilityManager::SetProfileForTest(Profile* profile) {
903 SetProfile(profile);
904}
905
[email protected]8c79e3f2013-10-30 01:05:14906void AccessibilityManager::SetBrailleControllerForTest(
907 BrailleController* controller) {
908 g_braille_controller_for_test = controller;
909}
910
[email protected]ce89d9392013-12-11 21:05:20911void AccessibilityManager::EnableSystemSounds(bool system_sounds_enabled) {
912 system_sounds_enabled_ = system_sounds_enabled;
913}
914
915base::TimeDelta AccessibilityManager::PlayShutdownSound() {
[email protected]4f011f12014-01-15 08:22:45916 if (!system_sounds_enabled_)
[email protected]ce89d9392013-12-11 21:05:20917 return base::TimeDelta();
918 system_sounds_enabled_ = false;
[email protected]c9eef112014-02-20 19:32:48919 if (!ash::PlaySystemSoundIfSpokenFeedback(SOUND_SHUTDOWN))
[email protected]4f011f12014-01-15 08:22:45920 return base::TimeDelta();
921 return media::SoundsManager::Get()->GetDuration(SOUND_SHUTDOWN);
[email protected]ce89d9392013-12-11 21:05:20922}
923
[email protected]f8aa76842014-02-05 19:11:06924void AccessibilityManager::InjectChromeVox(RenderViewHost* render_view_host) {
925 LoadChromeVoxExtension(profile_, render_view_host);
926}
927
[email protected]d8edc9c2014-02-25 00:06:03928scoped_ptr<AccessibilityStatusSubscription>
929 AccessibilityManager::RegisterCallback(
930 const AccessibilityStatusCallback& cb) {
931 return callback_list_.Add(cb);
932}
933
934void AccessibilityManager::NotifyAccessibilityStatusChanged(
935 AccessibilityStatusEventDetails& details) {
936 callback_list_.Notify(details);
937}
938
[email protected]1dfebfc2013-06-04 03:14:32939void AccessibilityManager::UpdateChromeOSAccessibilityHistograms() {
940 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSpokenFeedback",
941 IsSpokenFeedbackEnabled());
942 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosHighContrast",
943 IsHighContrastEnabled());
944 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosVirtualKeyboard",
[email protected]e1b299b2014-01-29 23:53:41945 IsVirtualKeyboardEnabled());
[email protected]7fb7ea42014-02-12 21:19:31946 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosStickyKeys", IsStickyKeysEnabled());
[email protected]1dfebfc2013-06-04 03:14:32947 if (MagnificationManager::Get()) {
948 uint32 type = MagnificationManager::Get()->IsMagnifierEnabled() ?
949 MagnificationManager::Get()->GetMagnifierType() : 0;
950 // '0' means magnifier is disabled.
951 UMA_HISTOGRAM_ENUMERATION("Accessibility.CrosScreenMagnifier",
952 type,
953 ash::kMaxMagnifierType + 1);
954 }
[email protected]ca3a0a82013-06-18 06:52:12955 if (profile_) {
956 const PrefService* const prefs = profile_->GetPrefs();
957 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosLargeCursor",
958 prefs->GetBoolean(prefs::kLargeCursorEnabled));
959 UMA_HISTOGRAM_BOOLEAN(
960 "Accessibility.CrosAlwaysShowA11yMenu",
961 prefs->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu));
[email protected]0b5a0d2b2013-10-30 03:43:40962
963 bool autoclick_enabled = prefs->GetBoolean(prefs::kAutoclickEnabled);
964 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosAutoclick", autoclick_enabled);
965 if (autoclick_enabled) {
966 // We only want to log the autoclick delay if the user has actually
967 // enabled autoclick.
968 UMA_HISTOGRAM_CUSTOM_TIMES(
969 "Accessibility.CrosAutoclickDelay",
970 base::TimeDelta::FromMilliseconds(
971 prefs->GetInteger(prefs::kAutoclickDelayMs)),
972 base::TimeDelta::FromMilliseconds(1),
973 base::TimeDelta::FromMilliseconds(3000),
974 50);
975 }
[email protected]ca3a0a82013-06-18 06:52:12976 }
[email protected]1dfebfc2013-06-04 03:14:32977}
978
979void AccessibilityManager::Observe(
980 int type,
981 const content::NotificationSource& source,
982 const content::NotificationDetails& details) {
983 switch (type) {
[email protected]093d9ba2013-07-23 19:26:21984 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
[email protected]9cf54f362013-07-01 07:28:12985 // Update |profile_| when entering the login screen.
[email protected]c20122572013-12-16 20:35:58986 Profile* profile = ProfileManager::GetActiveUserProfile();
[email protected]d888cdc2013-06-24 17:06:20987 if (ProfileHelper::IsSigninProfile(profile))
988 SetProfile(profile);
[email protected]1dfebfc2013-06-04 03:14:32989 break;
[email protected]d888cdc2013-06-24 17:06:20990 }
[email protected]e6f20642013-06-11 17:05:46991 case chrome::NOTIFICATION_SESSION_STARTED:
992 // Update |profile_| when entering a session.
[email protected]c20122572013-12-16 20:35:58993 SetProfile(ProfileManager::GetActiveUserProfile());
[email protected]0e9504d2013-11-05 02:33:29994
995 // Ensure ChromeVox makes announcements at the start of new sessions.
996 should_speak_chrome_vox_announcements_on_user_screen_ = true;
[email protected]c20122572013-12-16 20:35:58997
998 // Add a session state observer to be able to monitor session changes.
999 if (!session_state_observer_.get() && ash::Shell::HasInstance())
1000 session_state_observer_.reset(
1001 new ash::ScopedSessionStateObserver(this));
[email protected]1dfebfc2013-06-04 03:14:321002 break;
[email protected]1dfebfc2013-06-04 03:14:321003 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
[email protected]e6f20642013-06-11 17:05:461004 // Update |profile_| when exiting a session or shutting down.
1005 Profile* profile = content::Source<Profile>(source).ptr();
1006 if (profile_ == profile)
1007 SetProfile(NULL);
[email protected]1dfebfc2013-06-04 03:14:321008 break;
1009 }
[email protected]b0a2ce32013-07-23 15:24:531010 case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: {
1011 bool is_screen_locked = *content::Details<bool>(details).ptr();
[email protected]9d6c91362013-12-07 21:56:271012 if (spoken_feedback_enabled_) {
1013 if (is_screen_locked) {
[email protected]b0a2ce32013-07-23 15:24:531014 LoadChromeVoxToLockScreen();
[email protected]b0a2ce32013-07-23 15:24:531015
[email protected]9d6c91362013-12-07 21:56:271016 // Status tray gets verbalized by user screen ChromeVox, so we need
1017 // this as well.
[email protected]b0a2ce32013-07-23 15:24:531018 LoadChromeVoxToUserScreen();
[email protected]9d6c91362013-12-07 21:56:271019 } else {
[email protected]a4846a02014-04-21 19:11:451020 // If spoken feedback was enabled, also enable it on the user screen.
[email protected]9d6c91362013-12-07 21:56:271021 LoadChromeVoxToUserScreen();
1022 }
[email protected]b0a2ce32013-07-23 15:24:531023 }
[email protected]9d6c91362013-12-07 21:56:271024 break;
1025 }
[email protected]1dfebfc2013-06-04 03:14:321026 }
1027}
1028
[email protected]2e5e0b12014-05-07 13:30:201029void AccessibilityManager::OnBrailleDisplayStateChanged(
[email protected]8c79e3f2013-10-30 01:05:141030 const DisplayState& display_state) {
[email protected]a81b2c32014-03-28 06:35:011031 braille_display_connected_ = display_state.available;
[email protected]2e5e0b12014-05-07 13:30:201032 if (braille_display_connected_) {
[email protected]8c79e3f2013-10-30 01:05:141033 EnableSpokenFeedback(true, ash::A11Y_NOTIFICATION_SHOW);
[email protected]2e5e0b12014-05-07 13:30:201034 }
1035 UpdateBrailleImeState();
[email protected]a81b2c32014-03-28 06:35:011036
1037 AccessibilityStatusEventDetails details(
1038 ACCESSIBILITY_BRAILLE_DISPLAY_CONNECTION_STATE_CHANGED,
1039 braille_display_connected_,
1040 ash::A11Y_NOTIFICATION_SHOW);
1041 NotifyAccessibilityStatusChanged(details);
[email protected]8c79e3f2013-10-30 01:05:141042}
[email protected]0e9504d2013-11-05 02:33:291043
[email protected]2e5e0b12014-05-07 13:30:201044void AccessibilityManager::OnBrailleKeyEvent(const KeyEvent& event) {
1045 // Ensure the braille IME is active on braille keyboard (dots) input.
1046 if ((event.command ==
1047 extensions::api::braille_display_private::KEY_COMMAND_DOTS) &&
1048 !braille_ime_current_) {
1049 input_method::InputMethodManager::Get()->ChangeInputMethod(
1050 extension_misc::kBrailleImeEngineId);
1051 }
1052}
1053
[email protected]ee8bbd972014-02-03 06:52:471054void AccessibilityManager::PostLoadChromeVox(Profile* profile) {
1055 // Do any setup work needed immediately after ChromeVox actually loads.
[email protected]c9eef112014-02-20 19:32:481056 if (system_sounds_enabled_)
1057 ash::PlaySystemSoundAlways(SOUND_SPOKEN_FEEDBACK_ENABLED);
[email protected]0e9504d2013-11-05 02:33:291058
[email protected]c9eef112014-02-20 19:32:481059 ExtensionAccessibilityEventRouter::GetInstance()->
1060 OnChromeVoxLoadStateChanged(profile_,
1061 IsSpokenFeedbackEnabled(),
1062 chrome_vox_loaded_on_lock_screen_ ||
1063 should_speak_chrome_vox_announcements_on_user_screen_);
[email protected]0e9504d2013-11-05 02:33:291064
[email protected]c9eef112014-02-20 19:32:481065 should_speak_chrome_vox_announcements_on_user_screen_ =
1066 chrome_vox_loaded_on_lock_screen_;
[email protected]0e9504d2013-11-05 02:33:291067}
1068
[email protected]ee8bbd972014-02-03 06:52:471069void AccessibilityManager::PostUnloadChromeVox(Profile* profile) {
[email protected]9d6c91362013-12-07 21:56:271070 // Do any teardown work needed immediately after ChromeVox actually unloads.
[email protected]c9eef112014-02-20 19:32:481071 if (system_sounds_enabled_)
1072 ash::PlaySystemSoundAlways(SOUND_SPOKEN_FEEDBACK_DISABLED);
[email protected]9d6c91362013-12-07 21:56:271073}
1074
[email protected]1dfebfc2013-06-04 03:14:321075} // namespace chromeos