1 // 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 7 #include "ash/high_contrast/high_contrast_controller.h" 8 #include "ash/shell.h" 9 #include "ash/system/tray/system_tray_notifier.h" 10 #include "ash/wm/event_rewriter_event_filter.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/singleton.h" 13 #include "base/metrics/histogram.h" 14 #include "base/prefs/pref_member.h" 15 #include "base/prefs/pref_service.h" 16 #include "base/values.h" 17 #include "chrome/browser/accessibility/accessibility_extension_api.h" 18 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/chrome_notification_types.h" 20 #include "chrome/browser/chromeos/accessibility/magnification_manager.h" 21 #include "chrome/browser/chromeos/login/login_display_host.h" 22 #include "chrome/browser/chromeos/login/login_display_host_impl.h" 23 #include "chrome/browser/chromeos/login/screen_locker.h" 24 #include "chrome/browser/chromeos/login/webui_login_view.h" 25 #include "chrome/browser/chromeos/profiles/profile_helper.h" 26 #include "chrome/browser/extensions/component_loader.h" 27 #include "chrome/browser/extensions/extension_service.h" 28 #include "chrome/browser/extensions/extension_system.h" 29 #include "chrome/browser/profiles/profile.h" 30 #include "chrome/browser/profiles/profile_manager.h" 31 #include "chrome/browser/speech/tts_controller.h" 32 #include "chrome/common/extensions/extension.h" 33 #include "chrome/common/extensions/extension_messages.h" 34 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" 35 #include "chrome/common/pref_names.h" 36 #include "chromeos/login/login_state.h" 37 #include "content/public/browser/browser_accessibility_state.h" 38 #include "content/public/browser/notification_details.h" 39 #include "content/public/browser/notification_service.h" 40 #include "content/public/browser/notification_source.h" 41 #include "content/public/browser/render_process_host.h" 42 #include "content/public/browser/render_view_host.h" 43 #include "content/public/browser/web_contents.h" 44 #include "content/public/browser/web_ui.h" 45 #include "extensions/browser/file_reader.h" 46 #include "extensions/common/extension_resource.h" 47 #include "grit/browser_resources.h" 48 #include "grit/generated_resources.h" 49 #include "ui/base/l10n/l10n_util.h" 50 #include "ui/base/resource/resource_bundle.h" 51 52 using content::RenderViewHost; 53 54 namespace chromeos { 55 56 namespace { 57 58 static chromeos::AccessibilityManager* g_accessibility_manager = NULL; 59 60 // Helper class that directly loads an extension's content scripts into 61 // all of the frames corresponding to a given RenderViewHost. 62 class ContentScriptLoader { 63 public: 64 // Initialize the ContentScriptLoader with the ID of the extension 65 // and the RenderViewHost where the scripts should be loaded. 66 ContentScriptLoader(const std::string& extension_id, 67 int render_process_id, 68 int render_view_id) 69 : extension_id_(extension_id), 70 render_process_id_(render_process_id), 71 render_view_id_(render_view_id) {} 72 73 // Call this once with the ExtensionResource corresponding to each 74 // content script to be loaded. 75 void AppendScript(extensions::ExtensionResource resource) { 76 resources_.push(resource); 77 } 78 79 // Fianlly, call this method once to fetch all of the resources and 80 // load them. This method will delete this object when done. 81 void Run() { 82 if (resources_.empty()) { 83 delete this; 84 return; 85 } 86 87 extensions::ExtensionResource resource = resources_.front(); 88 resources_.pop(); 89 scoped_refptr<FileReader> reader(new FileReader(resource, base::Bind( 90 &ContentScriptLoader::OnFileLoaded, base::Unretained(this)))); 91 reader->Start(); 92 } 93 94 private: 95 void OnFileLoaded(bool success, const std::string& data) { 96 if (success) { 97 ExtensionMsg_ExecuteCode_Params params; 98 params.request_id = 0; 99 params.extension_id = extension_id_; 100 params.is_javascript = true; 101 params.code = data; 102 params.run_at = extensions::UserScript::DOCUMENT_IDLE; 103 params.all_frames = true; 104 params.in_main_world = false; 105 106 RenderViewHost* render_view_host = 107 RenderViewHost::FromID(render_process_id_, render_view_id_); 108 if (render_view_host) { 109 render_view_host->Send(new ExtensionMsg_ExecuteCode( 110 render_view_host->GetRoutingID(), params)); 111 } 112 } 113 Run(); 114 } 115 116 std::string extension_id_; 117 int render_process_id_; 118 int render_view_id_; 119 std::queue<extensions::ExtensionResource> resources_; 120 }; 121 122 void LoadChromeVoxExtension(Profile* profile, content::WebUI* login_web_ui) { 123 ExtensionService* extension_service = 124 extensions::ExtensionSystem::Get(profile)->extension_service(); 125 base::FilePath path = base::FilePath(extension_misc::kChromeVoxExtensionPath); 126 std::string extension_id = 127 extension_service->component_loader()->Add(IDR_CHROMEVOX_MANIFEST, 128 path); 129 if (login_web_ui) { 130 ExtensionService* extension_service = 131 extensions::ExtensionSystem::Get(profile)->extension_service(); 132 const extensions::Extension* extension = 133 extension_service->extensions()->GetByID(extension_id); 134 135 RenderViewHost* render_view_host = 136 login_web_ui->GetWebContents()->GetRenderViewHost(); 137 // Set a flag to tell ChromeVox that it's just been enabled, 138 // so that it won't interrupt our speech feedback enabled message. 139 ExtensionMsg_ExecuteCode_Params params; 140 params.request_id = 0; 141 params.extension_id = extension->id(); 142 params.is_javascript = true; 143 params.code = "window.INJECTED_AFTER_LOAD = true;"; 144 params.run_at = extensions::UserScript::DOCUMENT_IDLE; 145 params.all_frames = true; 146 params.in_main_world = false; 147 render_view_host->Send(new ExtensionMsg_ExecuteCode( 148 render_view_host->GetRoutingID(), params)); 149 150 // Inject ChromeVox' content scripts. 151 ContentScriptLoader* loader = new ContentScriptLoader( 152 extension->id(), render_view_host->GetProcess()->GetID(), 153 render_view_host->GetRoutingID()); 154 155 const extensions::UserScriptList& content_scripts = 156 extensions::ContentScriptsInfo::GetContentScripts(extension); 157 for (size_t i = 0; i < content_scripts.size(); i++) { 158 const extensions::UserScript& script = content_scripts[i]; 159 for (size_t j = 0; j < script.js_scripts().size(); ++j) { 160 const extensions::UserScript::File &file = script.js_scripts()[j]; 161 extensions::ExtensionResource resource = extension->GetResource( 162 file.relative_path()); 163 loader->AppendScript(resource); 164 } 165 } 166 loader->Run(); // It cleans itself up when done. 167 } 168 DLOG(INFO) << "ChromeVox was Loaded."; 169 } 170 171 void UnloadChromeVoxExtension(Profile* profile) { 172 ExtensionService* extension_service = 173 extensions::ExtensionSystem::Get(profile)->extension_service(); 174 base::FilePath path = base::FilePath(extension_misc::kChromeVoxExtensionPath); 175 extension_service->component_loader()->Remove(path); 176 DLOG(INFO) << "ChromeVox was Unloaded."; 177 } 178 179 } // namespace 180 181 /////////////////////////////////////////////////////////////////////////////// 182 // AccessibilityStatusEventDetails 183 184 AccessibilityStatusEventDetails::AccessibilityStatusEventDetails( 185 bool enabled, 186 ash::AccessibilityNotificationVisibility notify) 187 : enabled(enabled), 188 magnifier_type(ash::kDefaultMagnifierType), 189 notify(notify) {} 190 191 AccessibilityStatusEventDetails::AccessibilityStatusEventDetails( 192 bool enabled, 193 ash::MagnifierType magnifier_type, 194 ash::AccessibilityNotificationVisibility notify) 195 : enabled(enabled), 196 magnifier_type(magnifier_type), 197 notify(notify) {} 198 199 /////////////////////////////////////////////////////////////////////////////// 200 // 201 // AccessibilityManager::PrefHandler 202 203 AccessibilityManager::PrefHandler::PrefHandler(const char* pref_path) 204 : pref_path_(pref_path) {} 205 206 AccessibilityManager::PrefHandler::~PrefHandler() {} 207 208 void AccessibilityManager::PrefHandler::HandleProfileChanged( 209 Profile* previous_profile, Profile* current_profile) { 210 // Returns if the current profile is null. 211 if (!current_profile) 212 return; 213 214 // If the user set a pref value on the login screen and is now starting a 215 // session with a new profile, copy the pref value to the profile. 216 if ((previous_profile && 217 ProfileHelper::IsSigninProfile(previous_profile) && 218 current_profile->IsNewProfile() && 219 !ProfileHelper::IsSigninProfile(current_profile)) || 220 // Special case for Guest mode: 221 // Guest mode launches a guest-mode browser process before session starts, 222 // so the previous profile is null. 223 (!previous_profile && 224 current_profile->IsGuestSession())) { 225 // Returns if the pref has not been set by the user. 226 const PrefService::Preference* pref = ProfileHelper::GetSigninProfile()-> 227 GetPrefs()->FindPreference(pref_path_); 228 if (!pref || !pref->IsUserControlled()) 229 return; 230 231 // Copy the pref value from the signin screen. 232 const base::Value* value_on_login = pref->GetValue(); 233 PrefService* user_prefs = current_profile->GetPrefs(); 234 user_prefs->Set(pref_path_, *value_on_login); 235 } 236 } 237 238 /////////////////////////////////////////////////////////////////////////////// 239 // 240 // AccessibilityManager 241 242 // static 243 void AccessibilityManager::Initialize() { 244 CHECK(g_accessibility_manager == NULL); 245 g_accessibility_manager = new AccessibilityManager(); 246 } 247 248 // static 249 void AccessibilityManager::Shutdown() { 250 CHECK(g_accessibility_manager); 251 delete g_accessibility_manager; 252 g_accessibility_manager = NULL; 253 } 254 255 // static 256 AccessibilityManager* AccessibilityManager::Get() { 257 return g_accessibility_manager; 258 } 259 260 AccessibilityManager::AccessibilityManager() 261 : profile_(NULL), 262 chrome_vox_loaded_on_lock_screen_(false), 263 chrome_vox_loaded_on_user_screen_(false), 264 large_cursor_pref_handler_(prefs::kLargeCursorEnabled), 265 spoken_feedback_pref_handler_(prefs::kSpokenFeedbackEnabled), 266 high_contrast_pref_handler_(prefs::kHighContrastEnabled), 267 large_cursor_enabled_(false), 268 sticky_keys_enabled_(false), 269 spoken_feedback_enabled_(false), 270 high_contrast_enabled_(false), 271 spoken_feedback_notification_(ash::A11Y_NOTIFICATION_NONE) { 272 273 notification_registrar_.Add(this, 274 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 275 content::NotificationService::AllSources()); 276 notification_registrar_.Add(this, 277 chrome::NOTIFICATION_SESSION_STARTED, 278 content::NotificationService::AllSources()); 279 notification_registrar_.Add(this, 280 chrome::NOTIFICATION_PROFILE_DESTROYED, 281 content::NotificationService::AllSources()); 282 notification_registrar_.Add(this, 283 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, 284 content::NotificationService::AllSources()); 285 } 286 287 AccessibilityManager::~AccessibilityManager() { 288 CHECK(this == g_accessibility_manager); 289 } 290 291 void AccessibilityManager::EnableLargeCursor(bool enabled) { 292 if (!profile_) 293 return; 294 295 PrefService* pref_service = profile_->GetPrefs(); 296 pref_service->SetBoolean(prefs::kLargeCursorEnabled, enabled); 297 pref_service->CommitPendingWrite(); 298 } 299 300 void AccessibilityManager::UpdateLargeCursorFromPref() { 301 if (!profile_) 302 return; 303 304 const bool enabled = 305 profile_->GetPrefs()->GetBoolean(prefs::kLargeCursorEnabled); 306 307 if (large_cursor_enabled_ == enabled) 308 return; 309 310 large_cursor_enabled_ = enabled; 311 312 AccessibilityStatusEventDetails details(enabled, ash::A11Y_NOTIFICATION_NONE); 313 content::NotificationService::current()->Notify( 314 chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_LARGE_CURSOR, 315 content::NotificationService::AllSources(), 316 content::Details<AccessibilityStatusEventDetails>(&details)); 317 318 #if defined(USE_ASH) 319 // Large cursor is implemented only in ash. 320 ash::Shell::GetInstance()->cursor_manager()->SetScale(enabled ? 2.0 : 1.0); 321 #endif 322 } 323 324 bool AccessibilityManager::IsLargeCursorEnabled() { 325 return large_cursor_enabled_; 326 } 327 328 void AccessibilityManager::EnableStickyKeys(bool enabled) { 329 if (!profile_) 330 return; 331 PrefService* pref_service = profile_->GetPrefs(); 332 pref_service->SetBoolean(prefs::kStickyKeysEnabled, enabled); 333 pref_service->CommitPendingWrite(); 334 } 335 336 bool AccessibilityManager::IsStickyKeysEnabled() { 337 return sticky_keys_enabled_; 338 } 339 340 void AccessibilityManager::UpdateStickyKeysFromPref() { 341 if (!profile_) 342 return; 343 344 const bool enabled = 345 profile_->GetPrefs()->GetBoolean(prefs::kStickyKeysEnabled); 346 347 if (sticky_keys_enabled_ == enabled) 348 return; 349 350 sticky_keys_enabled_ = enabled; 351 #if defined(USE_ASH) 352 // Sticky keys is implemented only in ash. 353 ash::Shell::GetInstance()->event_rewriter_filter()->EnableStickyKeys(enabled); 354 #endif 355 } 356 357 void AccessibilityManager::EnableSpokenFeedback( 358 bool enabled, 359 ash::AccessibilityNotificationVisibility notify) { 360 if (!profile_) 361 return; 362 363 spoken_feedback_notification_ = notify; 364 365 PrefService* pref_service = profile_->GetPrefs(); 366 pref_service->SetBoolean( 367 prefs::kSpokenFeedbackEnabled, enabled); 368 pref_service->CommitPendingWrite(); 369 370 spoken_feedback_notification_ = ash::A11Y_NOTIFICATION_NONE; 371 } 372 373 void AccessibilityManager::UpdateSpokenFeedbackFromPref() { 374 if (!profile_) 375 return; 376 377 const bool enabled = 378 profile_->GetPrefs()->GetBoolean(prefs::kSpokenFeedbackEnabled); 379 380 if (spoken_feedback_enabled_ == enabled) 381 return; 382 383 spoken_feedback_enabled_ = enabled; 384 385 ExtensionAccessibilityEventRouter::GetInstance()-> 386 SetAccessibilityEnabled(enabled); 387 388 AccessibilityStatusEventDetails details(enabled, 389 spoken_feedback_notification_); 390 content::NotificationService::current()->Notify( 391 chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK, 392 content::NotificationService::AllSources(), 393 content::Details<AccessibilityStatusEventDetails>(&details)); 394 395 Speak(l10n_util::GetStringUTF8( 396 enabled ? IDS_CHROMEOS_ACC_SPOKEN_FEEDBACK_ENABLED : 397 IDS_CHROMEOS_ACC_SPOKEN_FEEDBACK_DISABLED).c_str()); 398 399 if (enabled) 400 LoadChromeVox(); 401 else 402 UnloadChromeVox(); 403 } 404 405 void AccessibilityManager::LoadChromeVox() { 406 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker(); 407 if (screen_locker && screen_locker->locked()) { 408 // If on the lock screen, loads ChromeVox only to the lock screen as for 409 // now. On unlock, it will be loaded to the user screen. 410 // (see. AccessibilityManager::Observe()) 411 LoadChromeVoxToLockScreen(); 412 return; 413 } 414 415 LoadChromeVoxToUserScreen(); 416 } 417 418 void AccessibilityManager::LoadChromeVoxToUserScreen() { 419 if (chrome_vox_loaded_on_user_screen_) 420 return; 421 422 // Determine whether an OOBE screen is currently being shown. If so, 423 // ChromeVox will be injected directly into that screen. 424 content::WebUI* login_web_ui = NULL; 425 426 if (ProfileHelper::IsSigninProfile(profile_)) { 427 LoginDisplayHost* login_display_host = LoginDisplayHostImpl::default_host(); 428 if (login_display_host) { 429 WebUILoginView* web_ui_login_view = 430 login_display_host->GetWebUILoginView(); 431 if (web_ui_login_view) 432 login_web_ui = web_ui_login_view->GetWebUI(); 433 } 434 } 435 436 LoadChromeVoxExtension(profile_, login_web_ui); 437 chrome_vox_loaded_on_user_screen_ = true; 438 } 439 440 void AccessibilityManager::LoadChromeVoxToLockScreen() { 441 if (chrome_vox_loaded_on_lock_screen_) 442 return; 443 444 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker(); 445 if (screen_locker && screen_locker->locked()) { 446 content::WebUI* lock_web_ui = screen_locker->GetAssociatedWebUI(); 447 if (lock_web_ui) { 448 Profile* profile = Profile::FromWebUI(lock_web_ui); 449 LoadChromeVoxExtension(profile, lock_web_ui); 450 chrome_vox_loaded_on_lock_screen_ = true; 451 } 452 } 453 } 454 455 void AccessibilityManager::UnloadChromeVox() { 456 if (chrome_vox_loaded_on_lock_screen_) 457 UnloadChromeVoxFromLockScreen(); 458 459 if (chrome_vox_loaded_on_user_screen_) { 460 UnloadChromeVoxExtension(profile_); 461 chrome_vox_loaded_on_user_screen_ = false; 462 } 463 } 464 465 void AccessibilityManager::UnloadChromeVoxFromLockScreen() { 466 // Lock screen uses the signin progile. 467 Profile* signin_profile = ProfileHelper::GetSigninProfile(); 468 UnloadChromeVoxExtension(signin_profile); 469 chrome_vox_loaded_on_lock_screen_ = false; 470 } 471 472 bool AccessibilityManager::IsSpokenFeedbackEnabled() { 473 return spoken_feedback_enabled_; 474 } 475 476 void AccessibilityManager::ToggleSpokenFeedback( 477 ash::AccessibilityNotificationVisibility notify) { 478 EnableSpokenFeedback(!IsSpokenFeedbackEnabled(), notify); 479 } 480 481 void AccessibilityManager::Speak(const std::string& text) { 482 UtteranceContinuousParameters params; 483 484 Utterance* utterance = new Utterance(profile_); 485 utterance->set_text(text); 486 utterance->set_lang(g_browser_process->GetApplicationLocale()); 487 utterance->set_continuous_parameters(params); 488 utterance->set_can_enqueue(false); 489 utterance->set_options(new DictionaryValue()); 490 491 TtsController* controller = TtsController::GetInstance(); 492 controller->SpeakOrEnqueue(utterance); 493 } 494 495 void AccessibilityManager::MaybeSpeak(const std::string& text) { 496 if (IsSpokenFeedbackEnabled()) 497 Speak(text); 498 } 499 500 void AccessibilityManager::EnableHighContrast(bool enabled) { 501 if (!profile_) 502 return; 503 504 PrefService* pref_service = profile_->GetPrefs(); 505 pref_service->SetBoolean(prefs::kHighContrastEnabled, enabled); 506 pref_service->CommitPendingWrite(); 507 } 508 509 void AccessibilityManager::UpdateHighContrastFromPref() { 510 if (!profile_) 511 return; 512 513 const bool enabled = 514 profile_->GetPrefs()->GetBoolean(prefs::kHighContrastEnabled); 515 516 if (high_contrast_enabled_ == enabled) 517 return; 518 519 high_contrast_enabled_ = enabled; 520 521 AccessibilityStatusEventDetails detail(enabled, ash::A11Y_NOTIFICATION_NONE); 522 content::NotificationService::current()->Notify( 523 chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_HIGH_CONTRAST_MODE, 524 content::NotificationService::AllSources(), 525 content::Details<AccessibilityStatusEventDetails>(&detail)); 526 527 #if defined(USE_ASH) 528 ash::Shell::GetInstance()->high_contrast_controller()->SetEnabled(enabled); 529 #endif 530 } 531 532 void AccessibilityManager::LocalePrefChanged() { 533 if (!profile_) 534 return; 535 536 if (!IsSpokenFeedbackEnabled()) 537 return; 538 539 // If the system locale changes and spoken feedback is enabled, 540 // reload ChromeVox so that it switches its internal translations 541 // to the new language. 542 EnableSpokenFeedback(false, ash::A11Y_NOTIFICATION_NONE); 543 EnableSpokenFeedback(true, ash::A11Y_NOTIFICATION_NONE); 544 } 545 546 bool AccessibilityManager::IsHighContrastEnabled() { 547 return high_contrast_enabled_; 548 } 549 550 void AccessibilityManager::SetProfile(Profile* profile) { 551 pref_change_registrar_.reset(); 552 local_state_pref_change_registrar_.reset(); 553 554 if (profile) { 555 // TODO(yoshiki): Move following code to PrefHandler. 556 pref_change_registrar_.reset(new PrefChangeRegistrar); 557 pref_change_registrar_->Init(profile->GetPrefs()); 558 pref_change_registrar_->Add( 559 prefs::kLargeCursorEnabled, 560 base::Bind(&AccessibilityManager::UpdateLargeCursorFromPref, 561 base::Unretained(this))); 562 pref_change_registrar_->Add( 563 prefs::kStickyKeysEnabled, 564 base::Bind(&AccessibilityManager::UpdateStickyKeysFromPref, 565 base::Unretained(this))); 566 pref_change_registrar_->Add( 567 prefs::kSpokenFeedbackEnabled, 568 base::Bind(&AccessibilityManager::UpdateSpokenFeedbackFromPref, 569 base::Unretained(this))); 570 pref_change_registrar_->Add( 571 prefs::kHighContrastEnabled, 572 base::Bind(&AccessibilityManager::UpdateHighContrastFromPref, 573 base::Unretained(this))); 574 575 local_state_pref_change_registrar_.reset(new PrefChangeRegistrar); 576 local_state_pref_change_registrar_->Init(g_browser_process->local_state()); 577 local_state_pref_change_registrar_->Add( 578 prefs::kApplicationLocale, 579 base::Bind(&AccessibilityManager::LocalePrefChanged, 580 base::Unretained(this))); 581 582 content::BrowserAccessibilityState::GetInstance()->AddHistogramCallback( 583 base::Bind( 584 &AccessibilityManager::UpdateChromeOSAccessibilityHistograms, 585 base::Unretained(this))); 586 } 587 588 large_cursor_pref_handler_.HandleProfileChanged(profile_, profile); 589 spoken_feedback_pref_handler_.HandleProfileChanged(profile_, profile); 590 high_contrast_pref_handler_.HandleProfileChanged(profile_, profile); 591 592 profile_ = profile; 593 UpdateLargeCursorFromPref(); 594 UpdateStickyKeysFromPref(); 595 UpdateSpokenFeedbackFromPref(); 596 UpdateHighContrastFromPref(); 597 } 598 599 void AccessibilityManager::SetProfileForTest(Profile* profile) { 600 SetProfile(profile); 601 } 602 603 void AccessibilityManager::UpdateChromeOSAccessibilityHistograms() { 604 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSpokenFeedback", 605 IsSpokenFeedbackEnabled()); 606 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosHighContrast", 607 IsHighContrastEnabled()); 608 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosVirtualKeyboard", 609 accessibility::IsVirtualKeyboardEnabled()); 610 if (MagnificationManager::Get()) { 611 uint32 type = MagnificationManager::Get()->IsMagnifierEnabled() ? 612 MagnificationManager::Get()->GetMagnifierType() : 0; 613 // '0' means magnifier is disabled. 614 UMA_HISTOGRAM_ENUMERATION("Accessibility.CrosScreenMagnifier", 615 type, 616 ash::kMaxMagnifierType + 1); 617 } 618 if (profile_) { 619 const PrefService* const prefs = profile_->GetPrefs(); 620 UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosLargeCursor", 621 prefs->GetBoolean(prefs::kLargeCursorEnabled)); 622 UMA_HISTOGRAM_BOOLEAN( 623 "Accessibility.CrosAlwaysShowA11yMenu", 624 prefs->GetBoolean(prefs::kShouldAlwaysShowAccessibilityMenu)); 625 } 626 } 627 628 void AccessibilityManager::Observe( 629 int type, 630 const content::NotificationSource& source, 631 const content::NotificationDetails& details) { 632 switch (type) { 633 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: { 634 // Update |profile_| when entering the login screen. 635 Profile* profile = ProfileManager::GetDefaultProfile(); 636 if (ProfileHelper::IsSigninProfile(profile)) 637 SetProfile(profile); 638 break; 639 } 640 case chrome::NOTIFICATION_SESSION_STARTED: 641 // Update |profile_| when entering a session. 642 SetProfile(ProfileManager::GetDefaultProfile()); 643 break; 644 case chrome::NOTIFICATION_PROFILE_DESTROYED: { 645 // Update |profile_| when exiting a session or shutting down. 646 Profile* profile = content::Source<Profile>(source).ptr(); 647 if (profile_ == profile) 648 SetProfile(NULL); 649 break; 650 } 651 case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: { 652 bool is_screen_locked = *content::Details<bool>(details).ptr(); 653 if (is_screen_locked) { 654 if (spoken_feedback_enabled_) 655 LoadChromeVoxToLockScreen(); 656 } else { 657 UnloadChromeVoxFromLockScreen(); 658 659 if (spoken_feedback_enabled_) 660 LoadChromeVoxToUserScreen(); 661 } 662 } 663 } 664 } 665 666 } // namespace chromeos 667